Browse Source

Merge pull request #644 from tendermint/release-v0.10.4

Release v0.10.4
pull/651/head v0.10.4
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
9af837c24d
97 changed files with 5338 additions and 2420 deletions
  1. +41
    -0
      CHANGELOG.md
  2. +10
    -22
      benchmarks/simu/counter.go
  3. +5
    -1
      cmd/tendermint/commands/root.go
  4. +18
    -6
      config/config.go
  5. +5
    -2
      consensus/reactor.go
  6. +6
    -0
      consensus/state.go
  7. +20
    -0
      docs/Makefile
  8. +14
    -0
      docs/README.md
  9. +255
    -0
      docs/abci-cli.rst
  10. +125
    -0
      docs/app-architecture.rst
  11. +299
    -0
      docs/app-development.rst
  12. +0
    -0
      docs/architecture/ABCI.md
  13. +0
    -0
      docs/architecture/README.md
  14. +0
    -0
      docs/architecture/adr-001.md
  15. +90
    -0
      docs/architecture/adr-002.md
  16. +0
    -0
      docs/architecture/adr-003.md
  17. BIN
      docs/architecture/img/tags1.png
  18. +0
    -0
      docs/architecture/merkle-frey.md
  19. +0
    -0
      docs/architecture/merkle.md
  20. BIN
      docs/assets/tmint-logo-blue.png
  21. +220
    -0
      docs/block-structure.rst
  22. +349
    -0
      docs/byzantine-consensus-algorithm.rst
  23. +171
    -0
      docs/conf.py
  24. +55
    -0
      docs/configuration.rst
  25. +47
    -0
      docs/deploy-testnets.rst
  26. +34
    -0
      docs/fast-sync.rst
  27. +73
    -0
      docs/genesis.rst
  28. +277
    -0
      docs/getting-started.rst
  29. +0
    -246
      docs/getting-started/#02-first-app.md
  30. +0
    -39
      docs/getting-started/#03-deploy-testnet.md
  31. +0
    -21
      docs/getting-started/#04-next-steps.md
  32. +0
    -219
      docs/guides/abci-cli.md
  33. +0
    -64
      docs/guides/app-architecture.md
  34. +0
    -155
      docs/guides/app-development.md
  35. +0
    -100
      docs/guides/install-from-source.md
  36. +0
    -306
      docs/guides/using-tendermint.md
  37. BIN
      docs/images/abci.png
  38. BIN
      docs/images/consensus_logic.png
  39. BIN
      docs/images/tm-transaction-flow.png
  40. BIN
      docs/images/tmint-logo-blue.png
  41. +0
    -28
      docs/index.md
  42. +52
    -0
      docs/index.rst
  43. +102
    -0
      docs/install.rst
  44. +231
    -0
      docs/introduction.rst
  45. +33
    -0
      docs/light-client-protocol.rst
  46. +88
    -0
      docs/merkle.rst
  47. +4
    -0
      docs/requirements.txt
  48. +188
    -0
      docs/rpc.rst
  49. +73
    -0
      docs/secure-p2p.rst
  50. +20
    -0
      docs/specification.rst
  51. +0
    -168
      docs/specs/block-structure.md
  52. +0
    -191
      docs/specs/byzantine-consensus-algorithm.md
  53. +0
    -36
      docs/specs/configuration.md
  54. +0
    -13
      docs/specs/fast-sync.md
  55. +0
    -61
      docs/specs/genesis.md
  56. +0
    -15
      docs/specs/light-client-protocol.md
  57. +0
    -45
      docs/specs/merkle.md
  58. +0
    -156
      docs/specs/rpc.md
  59. +0
    -33
      docs/specs/secure-p2p.md
  60. +0
    -2
      docs/specs/tendermint-types.md
  61. +0
    -21
      docs/specs/validators.md
  62. +0
    -119
      docs/specs/wire-protocol.md
  63. +356
    -0
      docs/using-tendermint.rst
  64. +44
    -0
      docs/validators.rst
  65. +172
    -0
      docs/wire-protocol.rst
  66. +4
    -3
      glide.lock
  67. +11
    -9
      glide.yaml
  68. +6
    -4
      mempool/mempool.go
  69. +8
    -10
      mempool/mempool_test.go
  70. +8
    -5
      mempool/reactor.go
  71. +108
    -0
      mempool/reactor_test.go
  72. +2
    -2
      node/node.go
  73. +34
    -22
      p2p/connection.go
  74. +1
    -1
      p2p/pex_reactor_test.go
  75. +8
    -2
      p2p/switch.go
  76. +0
    -41
      roadmap.md
  77. +4
    -3
      rpc/client/httpclient.go
  78. +15
    -0
      rpc/core/README.md
  79. +64
    -2
      rpc/core/abci.go
  80. +221
    -7
      rpc/core/blocks.go
  81. +59
    -1
      rpc/core/consensus.go
  82. +107
    -0
      rpc/core/doc.go
  83. +8
    -0
      rpc/core/doc_template.txt
  84. +54
    -0
      rpc/core/events.go
  85. +150
    -1
      rpc/core/mempool.go
  86. +64
    -7
      rpc/core/net.go
  87. +47
    -0
      rpc/core/status.go
  88. +57
    -2
      rpc/core/tx.go
  89. +1
    -1
      rpc/grpc/grpc_test.go
  90. +386
    -90
      rpc/lib/client/ws_client.go
  91. +193
    -0
      rpc/lib/client/ws_client_test.go
  92. +53
    -14
      rpc/lib/rpc_test.go
  93. +140
    -94
      rpc/lib/server/handlers.go
  94. +13
    -0
      rpc/lib/types/types.go
  95. +9
    -6
      state/execution.go
  96. +24
    -22
      state/state.go
  97. +2
    -2
      version/version.go

+ 41
- 0
CHANGELOG.md View File

@ -1,5 +1,46 @@
# Changelog
## Roadmap
BREAKING CHANGES:
- Upgrade the header to support better proves on validtors, results, evidence, and possibly more
- Better support for injecting randomness
- Pass evidence/voteInfo through ABCI
- Upgrade consensus for more real-time use of evidence
FEATURES:
- Peer reputation management
- Use the chain as its own CA for nodes and validators
- Tooling to run multiple blockchains/apps, possibly in a single process
- State syncing (without transaction replay)
- Improved support for querying history and state
- Add authentication and rate-limitting to the RPC
IMPROVEMENTS:
- Improve subtleties around mempool caching and logic
- Consensus optimizations:
- cache block parts for faster agreement after round changes
- propagate block parts rarest first
- Better testing of the consensus state machine (ie. use a DSL)
- Auto compiled serialization/deserialization code instead of go-wire reflection
BUG FIXES:
- Graceful handling/recovery for apps that have non-determinism or fail to halt
- Graceful handling/recovery for violations of safety, or liveness
## 0.10.4 (Septemeber 5, 2017)
IMPROVEMENTS:
- docs: Added Slate docs to each rpc function (see rpc/core)
- docs: Ported all website docs to Read The Docs
- config: expose some p2p params to tweak performance: RecvRate, SendRate, and MaxMsgPacketPayloadSize
- rpc: Upgrade the websocket client and server, including improved auto reconnect, and proper ping/pong
BUG FIXES:
- consensus: fix panic on getVoteBitArray
- consensus: hang instead of panicking on byzantine consensus failures
- cmd: dont load config for version command
## 0.10.3 (August 10, 2017)
FEATURES:


+ 10
- 22
benchmarks/simu/counter.go View File

@ -1,30 +1,28 @@
package main
import (
"context"
"encoding/binary"
"time"
//"encoding/hex"
"fmt"
"github.com/gorilla/websocket"
"github.com/tendermint/go-wire"
_ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types
"github.com/tendermint/tendermint/rpc/lib/client"
"github.com/tendermint/tendermint/rpc/lib/types"
. "github.com/tendermint/tmlibs/common"
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
cmn "github.com/tendermint/tmlibs/common"
)
func main() {
ws := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket")
_, err := ws.Start()
wsc := rpcclient.NewWSClient("127.0.0.1:46657", "/websocket")
_, err := wsc.Start()
if err != nil {
Exit(err.Error())
cmn.Exit(err.Error())
}
defer wsc.Stop()
// Read a bunch of responses
go func() {
for {
_, ok := <-ws.ResultsCh
_, ok := <-wsc.ResultsCh
if !ok {
break
}
@ -37,24 +35,14 @@ func main() {
for i := 0; ; i++ {
binary.BigEndian.PutUint64(buf, uint64(i))
//txBytes := hex.EncodeToString(buf[:n])
request, err := rpctypes.MapToRequest("fakeid",
"broadcast_tx",
map[string]interface{}{"tx": buf[:8]})
if err != nil {
Exit(err.Error())
}
reqBytes := wire.JSONBytes(request)
//fmt.Println("!!", string(reqBytes))
fmt.Print(".")
err = ws.WriteMessage(websocket.TextMessage, reqBytes)
err = wsc.Call(context.TODO(), "broadcast_tx", map[string]interface{}{"tx": buf[:8]})
if err != nil {
Exit(err.Error())
cmn.Exit(err.Error())
}
if i%1000 == 0 {
fmt.Println(i)
}
time.Sleep(time.Microsecond * 1000)
}
ws.Stop()
}

+ 5
- 1
cmd/tendermint/commands/root.go View File

@ -21,7 +21,8 @@ func init() {
RootCmd.PersistentFlags().String("log_level", config.LogLevel, "Log level")
}
// ParseConfig will setup the tendermint configuration properly
// ParseConfig retrieves the default environment configuration,
// sets up the Tendermint root and ensures that the root exists
func ParseConfig() (*cfg.Config, error) {
conf := cfg.DefaultConfig()
err := viper.Unmarshal(conf)
@ -37,6 +38,9 @@ var RootCmd = &cobra.Command{
Use: "tendermint",
Short: "Tendermint Core (BFT Consensus) in Go",
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
if cmd.Name() == versionCmd.Name() {
return nil
}
config, err = ParseConfig()
if err != nil {
return err


+ 18
- 6
config/config.go View File

@ -222,18 +222,30 @@ type P2PConfig struct {
// Maximum number of peers to connect to
MaxNumPeers int `mapstructure:"max_num_peers"`
// Time to wait before flushing messages out on the connection. In ms
// Time to wait before flushing messages out on the connection, in ms
FlushThrottleTimeout int `mapstructure:"flush_throttle_timeout"`
// Maximum size of a message packet payload, in bytes
MaxMsgPacketPayloadSize int `mapstructure:"max_msg_packet_payload_size"`
// Rate at which packets can be sent, in bytes/second
SendRate int64 `mapstructure:"send_rate"`
// Rate at which packets can be received, in bytes/second
RecvRate int64 `mapstructure:"recv_rate"`
}
// DefaultP2PConfig returns a default configuration for the peer-to-peer layer
func DefaultP2PConfig() *P2PConfig {
return &P2PConfig{
ListenAddress: "tcp://0.0.0.0:46656",
AddrBook: "addrbook.json",
AddrBookStrict: true,
MaxNumPeers: 50,
FlushThrottleTimeout: 100,
ListenAddress: "tcp://0.0.0.0:46656",
AddrBook: "addrbook.json",
AddrBookStrict: true,
MaxNumPeers: 50,
FlushThrottleTimeout: 100,
MaxMsgPacketPayloadSize: 1024, // 1 kB
SendRate: 512000, // 500 kB/s
RecvRate: 512000, // 500 kB/s
}
}


+ 5
- 2
consensus/reactor.go View File

@ -918,7 +918,7 @@ func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote
func (ps *PeerState) getVoteBitArray(height, round int, type_ byte) *cmn.BitArray {
if !types.IsVoteTypeValid(type_) {
cmn.PanicSanity("Invalid vote type")
return nil
}
if ps.Height == height {
@ -1029,7 +1029,10 @@ func (ps *PeerState) setHasVote(height int, round int, type_ byte, index int) {
logger.Debug("setHasVote(LastCommit)", "lastCommit", ps.LastCommit, "index", index)
// NOTE: some may be nil BitArrays -> no side effects.
ps.getVoteBitArray(height, round, type_).SetIndex(index, true)
psVotes := ps.getVoteBitArray(height, round, type_)
if psVotes != nil {
psVotes.SetIndex(index, true)
}
}
// ApplyNewRoundStepMessage updates the peer state for the new round.


+ 6
- 0
consensus/state.go View File

@ -615,6 +615,12 @@ func (cs *ConsensusState) newStep() {
// Updates (state transitions) happen on timeouts, complete proposals, and 2/3 majorities.
// ConsensusState must be locked before any internal state is updated.
func (cs *ConsensusState) receiveRoutine(maxSteps int) {
defer func() {
if r := recover(); r != nil {
cs.Logger.Error("CONSENSUS FAILURE!!!", "err", r)
}
}()
for {
if maxSteps > 0 {
if cs.nSteps >= maxSteps {


+ 20
- 0
docs/Makefile View File

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = python -msphinx
SPHINXPROJ = Tendermint
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

+ 14
- 0
docs/README.md View File

@ -0,0 +1,14 @@
Here lies our documentation. After making edits, run:
```
pip install -r requirements.txt
make html
```
to build the docs locally then open the file `_build/html/index.html` in your browser.
**WARNING:** This documentation is intended to be viewed at:
https://tendermint.readthedocs.io
and may contain broken internal links when viewed from Github.

+ 255
- 0
docs/abci-cli.rst View File

@ -0,0 +1,255 @@
Using the abci-cli
==================
To facilitate testing and debugging of ABCI servers and simple apps, we
built a CLI, the ``abci-cli``, for sending ABCI messages from the
command line.
Install
-------
Make sure you `have Go installed <https://golang.org/doc/install>`__.
Next, install the ``abci-cli`` tool and example applications:
::
go get -u github.com/tendermint/abci/cmd/...
If this fails, you may need to use ``glide`` to get vendored
dependencies:
::
go get github.com/Masterminds/glide
cd $GOPATH/src/github.com/tendermint/abci
glide install
go install ./cmd/...
Now run ``abci-cli --help`` to see the list of commands:
::
COMMANDS:
batch Run a batch of ABCI commands against an application
console Start an interactive console for multiple commands
echo Have the application echo a message
info Get some info about the application
set_option Set an option on the application
deliver_tx Append a new tx to application
check_tx Validate a tx
commit Get application Merkle root hash
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--address "tcp://127.0.0.1:46658" address of application socket
--help, -h show help
--version, -v print the version
Dummy - First Example
---------------------
The ``abci-cli`` tool lets us send ABCI messages to our application, to
help build and debug them.
The most important messages are ``deliver_tx``, ``check_tx``, and
``commit``, but there are others for convenience, configuration, and
information purposes.
Let's start a dummy application, which was installed at the same time as
``abci-cli`` above. The dummy just stores transactions in a merkle tree:
::
dummy
In another terminal, run
::
abci-cli echo hello
abci-cli info
The application should echo ``hello`` and give you some information
about itself.
An ABCI application must provide two things:
- a socket server
- a handler for ABCI messages
When we run the ``abci-cli`` tool we open a new connection to the
application's socket server, send the given ABCI message, and wait for a
response.
The server may be generic for a particular language, and we provide a
`reference implementation in
Golang <https://github.com/tendermint/abci/tree/master/server>`__. See
the `list of other ABCI
implementations <https://tendermint.com/ecosystem>`__ for servers in
other languages.
The handler is specific to the application, and may be arbitrary, so
long as it is deterministic and conforms to the ABCI interface
specification.
So when we run ``abci-cli info``, we open a new connection to the ABCI
server, which calls the ``Info()`` method on the application, which
tells us the number of transactions in our Merkle tree.
Now, since every command opens a new connection, we provide the
``abci-cli console`` and ``abci-cli batch`` commands, to allow multiple
ABCI messages to be sent over a single connection.
Running ``abci-cli console`` should drop you in an interactive console
for speaking ABCI messages to your application.
Try running these commands:
::
> echo hello
-> data: hello
> info
-> data: {"size":0}
> commit
-> data: 0x
> deliver_tx "abc"
-> code: OK
> info
-> data: {"size":1}
> commit
-> data: 0x750502FC7E84BBD788ED589624F06CFA871845D1
> query "abc"
-> code: OK
-> data: {"index":0,"value":"abc","exists":true}
> deliver_tx "def=xyz"
-> code: OK
> commit
-> data: 0x76393B8A182E450286B0694C629ECB51B286EFD5
> query "def"
-> code: OK
-> data: {"index":1,"value":"xyz","exists":true}
Note that if we do ``deliver_tx "abc"`` it will store ``(abc, abc)``,
but if we do ``deliver_tx "abc=efg"`` it will store ``(abc, efg)``.
Similarly, you could put the commands in a file and run
``abci-cli --verbose batch < myfile``.
Counter - Another Example
-------------------------
Now that we've got the hang of it, let's try another application, the
"counter" app.
The counter app doesn't use a Merkle tree, it just counts how many times
we've sent a transaction, asked for a hash, or committed the state. The
result of ``commit`` is just the number of transactions sent.
This application has two modes: ``serial=off`` and ``serial=on``.
When ``serial=on``, transactions must be a big-endian encoded
incrementing integer, starting at 0.
If ``serial=off``, there are no restrictions on transactions.
We can toggle the value of ``serial`` using the ``set_option`` ABCI
message.
When ``serial=on``, some transactions are invalid. In a live blockchain,
transactions collect in memory before they are committed into blocks. To
avoid wasting resources on invalid transactions, ABCI provides the
``check_tx`` message, which application developers can use to accept or
reject transactions, before they are stored in memory or gossipped to
other peers.
In this instance of the counter app, ``check_tx`` only allows
transactions whose integer is greater than the last committed one.
Let's kill the console and the dummy application, and start the counter
app:
::
counter
In another window, start the ``abci-cli console``:
::
> set_option serial on
-> data: serial=on
> 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
-> data: {"hashes":0,"txs":2}
This is a very simple application, but between ``counter`` and
``dummy``, its easy to see how you can build out arbitrary application
states on top of the ABCI. `Hyperledger's
Burrow <https://github.com/hyperledger/burrow>`__ also runs atop ABCI,
bringing with it Ethereum-like accounts, the Ethereum virtual-machine,
Monax's permissioning scheme, and native contracts extensions.
But the ultimate flexibility comes from being able to write the
application easily in any language.
We have implemented the counter in a number of languages (see the
example directory).
To run the Node JS version, ``cd`` to ``example/js`` and run
::
node app.js
(you'll have to kill the other counter application process). In another
window, run the console and those previous ABCI commands. You should get
the same results as for the Go version.
Bounties
--------
Want to write the counter app in your favorite language?! We'd be happy
to add you to our `ecosystem <https://tendermint.com/ecosystem>`__!
We're also offering `bounties <https://tendermint.com/bounties>`__ for
implementations in new languages!
The ``abci-cli`` is designed strictly for testing and debugging. In a
real deployment, the role of sending messages is taken by Tendermint,
which connects to the app using three separate connections, each with
its own pattern of messages.
For more information, see the `application developers
guide <./app-development.html>`__. For examples of running an ABCI
app with Tendermint, see the `getting started
guide <./getting-started.html>`__.

+ 125
- 0
docs/app-architecture.rst View File

@ -0,0 +1,125 @@
Application Architecture Guide
==============================
Overview
--------
A blockchain application is more than the consensus engine and the
transaction logic (eg. smart contracts, business logic) as implemented
in the ABCI app. There are also (mobile, web, desktop) clients that will
need to connect and make use of the app. We will assume for now that you
have a well designed transactions and database model, but maybe this
will be the topic of another article. This article is more interested in
various ways of setting up the "plumbing" and connecting these pieces,
and demonstrating some evolving best practices.
Security
--------
A very important aspect when constructing a blockchain is security. The
consensus model can be DoSed (no consensus possible) by corrupting 1/3
of the validators and exploited (writing arbitrary blocks) by corrupting
2/3 of the validators. So, while the security is not that of the
"weakest link", you should take care that the "average link" is
sufficiently hardened.
One big attack surface on the validators is the communication between
the ABCI app and the tendermint core. This should be highly protected.
Ideally, the app and the core are running on the same machine, so no
external agent can target the communication channel. You can use unix
sockets (with permissions preventing access from other users), or even
compile the two apps into one binary if the ABCI app is also writen in
go. If you are unable to do that due to language support, then the ABCI
app should bind a TCP connection to localhost (127.0.0.1), which is less
efficient and secure, but still not reachable from outside. If you must
run the ABCI app and tendermint core on separate machines, make sure you
have a secure communication channel (ssh tunnel?)
Now assuming, you have linked together your app and the core securely,
you must also make sure no one can get on the machine it is hosted on.
At this point it is basic network security. Run on a secure operating
system (SELinux?). Limit who has access to the machine (user accounts,
but also where the physical machine is hosted). Turn off all services
except for ssh, which should only be accessible by some well-guarded
public/private key pairs (no password). And maybe even firewall off
access to the ports used by the validators, so only known validators can
connect.
There was also a suggestion on slack from @jhon about compiling
everything together with a unikernel for more security, such as
`Mirage <https://mirage.io>`__ or
`UNIK <https://github.com/emc-advanced-dev/unik>`__.
Connecting your client to the blockchain
----------------------------------------
Tendermint Core RPC
~~~~~~~~~~~~~~~~~~~
The concept is that the ABCI app is completely hidden from the outside
world and only communicated through a tested and secured `interface
exposed by the tendermint core <./rpc.html>`__. This interface
exposes a lot of data on the block header and consensus process, which
is quite useful for externally verifying the system. It also includes
3(!) methods to broadcast a transaction (propose it for the blockchain,
and possibly await a response). And one method to query app-specific
data from the ABCI application.
Pros:
* Server code already written
* Access to block headers to validate merkle proofs (nice for light clients)
* Basic read/write functionality is supported
Cons:
* Limited interface to app. All queries must be serialized into
[]byte (less expressive than JSON over HTTP) and there is no way to push
data from ABCI app to the client (eg. notify me if account X receives a
transaction)
Custom ABCI server
~~~~~~~~~~~~~~~~~~
This was proposed by @wolfposd on slack and demonstrated by
`TMChat <https://github.com/wolfposd/TMChat>`__, a sample app. The
concept is to write a custom server for your app (with typical REST
API/websockets/etc for easy use by a mobile app). This custom server is
in the same binary as the ABCI app and data store, so can easily react
to complex events there that involve understanding the data format (send
a message if my balance drops below 500). All "writes" sent to this
server are proxied via websocket/JSON-RPC to tendermint core. When they
come back as deliver\_tx over ABCI, they will be written to the data
store. For "reads", we can do any queries we wish that are supported by
our architecture, using any web technology that is useful. The general
architecture is shown in the following diagram:
Pros: \* Separates application logic from blockchain logic \* Allows
much richer, more flexible client-facing API \* Allows pub-sub, watching
certain fields, etc.
Cons: \* Access to ABCI app can be dangerous (be VERY careful not to
write unless it comes from the validator node) \* No direct access to
the blockchain headers to verify tx \* You must write your own API (but
maybe that's a pro...)
Hybrid solutions
~~~~~~~~~~~~~~~~
Likely the least secure but most versatile. The client can access both
the tendermint node for all blockchain info, as well as a custom app
server, for complex queries and pub-sub on the abci app.
Pros: All from both above solutions
Cons: Even more complexity; even more attack vectors (less
security)
Scalability
-----------
Read replica using non-validating nodes? They could forward transactions
to the validators (fewer connections, more security), and locally allow
all queries in any of the above configurations. Thus, while
transaction-processing speed is limited by the speed of the abci app and
the number of validators, one should be able to scale our read
performance to quite an extent (until the replication process drains too
many resources from the validator nodes).

+ 299
- 0
docs/app-development.rst View File

@ -0,0 +1,299 @@
Application Development Guide
=============================
ABCI Design
-----------
The purpose of ABCI is to provide a clean interface between state
transition machines on one computer and the mechanics of their
replication across multiple computers. The former we call 'application
logic' and the latter the 'consensus engine'. Application logic
validates transactions and optionally executes transactions against some
persistent state. A consensus engine ensures all transactions are
replicated in the same order on every machine. We call each machine in a
consensus engine a 'validator', and each validator runs the same
transactions through the same application logic. In particular, we are
interested in blockchain-style consensus engines, where transactions are
committed in hash-linked blocks.
The ABCI design has a few distinct components:
- message protocol
- pairs of request and response messages
- consensus makes requests, application responds
- defined using protobuf
- server/client
- consensus engine runs the client
- application runs the server
- two implementations:
- async raw bytes
- grpc
- blockchain protocol
- abci is connection oriented
- Tendermint Core maintains three connections:
- `mempool connection <#mempool-connection>`__: for checking if
transactions should be relayed before they are committed; only
uses ``CheckTx``
- `consensus connection <#consensus-connection>`__: for executing
transactions that have been committed. Message sequence is -
for every block -
``BeginBlock, [DeliverTx, ...], EndBlock, Commit``
- `query connection <#query-connection>`__: for querying the
application state; only uses Query and Info
The mempool and consensus logic act as clients, and each maintains an
open ABCI connection with the application, which hosts an ABCI server.
Shown are the request and response types sent on each connection.
Message Protocol
----------------
The message protocol consists of pairs of requests and responses. Some
messages have no fields, while others may include byte-arrays, strings,
or integers. See the ``message Request`` and ``message Response``
definitions in `the protobuf definition
file <https://github.com/tendermint/abci/blob/master/types/types.proto>`__,
and the `protobuf
documentation <https://developers.google.com/protocol-buffers/docs/overview>`__
for more details.
For each request, a server should respond with the corresponding
response, where order of requests is preserved in the order of
responses.
Server
------
To use ABCI in your programming language of choice, there must be a ABCI
server in that language. Tendermint supports two kinds of implementation
of the server:
- Asynchronous, raw socket server (Tendermint Socket Protocol, also
known as TSP or Teaspoon)
- GRPC
Both can be tested using the ``abci-cli`` by setting the ``--abci`` flag
appropriately (ie. to ``socket`` or ``grpc``).
See examples, in various stages of maintenance, in
`Go <https://github.com/tendermint/abci/tree/master/server>`__,
`JavaScript <https://github.com/tendermint/js-abci>`__,
`Python <https://github.com/tendermint/abci/tree/master/example/python3/abci>`__,
`C++ <https://github.com/mdyring/cpp-tmsp>`__, and
`Java <https://github.com/jTendermint/jabci>`__.
GRPC
~~~~
If GRPC is available in your language, this is the easiest approach,
though it will have significant performance overhead.
To get started with GRPC, copy in the `protobuf
file <https://github.com/tendermint/abci/blob/master/types/types.proto>`__
and compile it using the GRPC plugin for your language. For instance,
for golang, the command is
``protoc --go_out=plugins=grpc:. types.proto``. See the `grpc
documentation for more details <http://www.grpc.io/docs/>`__. ``protoc``
will autogenerate all the necessary code for ABCI client and server in
your language, including whatever interface your application must
satisfy to be used by the ABCI server for handling requests.
TSP
~~~
If GRPC is not available in your language, or you require higher
performance, or otherwise enjoy programming, you may implement your own
ABCI server using the Tendermint Socket Protocol, known affectionately
as Teaspoon. The first step is still to auto-generate the relevant data
types and codec in your language using ``protoc``. Messages coming over
the socket are Protobuf3 encoded, but additionally length-prefixed to
facilitate use as a streaming protocol. Protobuf3 doesn't have an
official length-prefix standard, so we use our own. The first byte in
the prefix represents the length of the Big Endian encoded length. The
remaining bytes in the prefix are 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....
Note this prefixing does not apply for grpc.
An ABCI server must also be able to support multiple connections, as
Tendermint uses three connections.
Client
------
There are currently two use-cases for an ABCI client. One is a testing
tool, as in the ``abci-cli``, which allows ABCI requests to be sent via
command line. The other is a consensus engine, such as Tendermint Core,
which makes requests to the application every time a new transaction is
received or a block is committed.
It is unlikely that you will need to implement a client. For details of
our client, see
`here <https://github.com/tendermint/abci/tree/master/client>`__.
Blockchain Protocol
-------------------
In ABCI, a transaction is simply an arbitrary length byte-array. It is
the application's responsibility to define the transaction codec as they
please, and to use it for both CheckTx and DeliverTx.
Note that there are two distinct means for running transactions,
corresponding to stages of 'awareness' of the transaction in the
network. The first stage is when a transaction is received by a
validator from a client into the so-called mempool or transaction pool -
this is where we use CheckTx. The second is when the transaction is
successfully committed on more than 2/3 of validators - where we use
DeliverTx. In the former case, it may not be necessary to run all the
state transitions associated with the transaction, as the transaction
may not ultimately be committed until some much later time, when the
result of its execution will be different. For instance, an Ethereum
ABCI app would check signatures and amounts in CheckTx, but would not
actually execute any contract code until the DeliverTx, so as to avoid
executing state transitions that have not been finalized.
To formalize the distinction further, two explicit ABCI connections are
made between Tendermint Core and the application: the mempool connection
and the consensus connection. We also make a third connection, the query
connection, to query the local state of the app.
Mempool Connection
~~~~~~~~~~~~~~~~~~
The mempool connection is used *only* for CheckTx requests. Transactions
are run using CheckTx in the same order they were received by the
validator. If the CheckTx returns ``OK``, the transaction is kept in
memory and relayed to other peers in the same order it was received.
Otherwise, it is discarded.
CheckTx requests run concurrently with block processing; so they should
run against a copy of the main application state which is reset after
every block. This copy is necessary to track transitions made by a
sequence of CheckTx requests before they are included in a block. When a
block is committed, the application must ensure to reset the mempool
state to the latest committed state. Tendermint Core will then filter
through all transactions in the mempool, removing any that were included
in the block, and re-run the rest using CheckTx against the post-Commit
mempool state.
Consensus Connection
~~~~~~~~~~~~~~~~~~~~
The consensus connection is used only when a new block is committed, and
communicates all information from the block in a series of requests:
``BeginBlock, [DeliverTx, ...], EndBlock, Commit``. That is, when a
block is committed in the consensus, we send a list of DeliverTx
requests (one for each transaction) sandwiched by BeginBlock and
EndBlock requests, and followed by a Commit.
DeliverTx
^^^^^^^^^
DeliverTx is the workhorse of the blockchain. Tendermint sends the
DeliverTx requests asynchronously but in order, and relies on the
underlying socket protocol (ie. TCP) to ensure they are received by the
app in order. They have already been ordered in the global consensus by
the Tendermint protocol.
DeliverTx returns a abci.Result, which includes a Code, Data, and Log.
The code may be non-zero (non-OK), meaning the corresponding transaction
should have been rejected by the mempool, but may have been included in
a block by a Byzantine proposer.
The block header will be updated (TODO) to include some commitment to
the results of DeliverTx, be it a bitarray of non-OK transactions, or a
merkle root of the data returned by the DeliverTx requests, or both.
Commit
^^^^^^
Once all processing of the block is complete, Tendermint sends the
Commit request and blocks waiting for a response. While the mempool may
run concurrently with block processing (the BeginBlock, DeliverTxs, and
EndBlock), it is locked for the Commit request so that its state can be
safely reset during Commit. This means the app *MUST NOT* do any
blocking communication with the mempool (ie. broadcast\_tx) during
Commit, or there will be deadlock. Note also that all remaining
transactions in the mempool are replayed on the mempool connection
(CheckTx) following a commit.
The Commit response includes a byte array, which is the deterministic
state root of the application. It is included in the header of the next
block. It can be used to provide easily verified Merkle-proofs of the
state of the application.
It is expected that the app will persist state to disk on Commit. The
option to have all transactions replayed from some previous block is the
job of the `Handshake <#handshake>`__.
BeginBlock
^^^^^^^^^^
The BeginBlock request can be used to run some code at the beginning of
every block. It also allows Tendermint to send the current block hash
and header to the application, before it sends any of the transactions.
The app should remember the latest height and header (ie. from which it
has run a successful Commit) so that it can tell Tendermint where to
pick up from when it restarts. See information on the Handshake, below.
EndBlock
^^^^^^^^
The EndBlock request can be used to run some code at the end of every
block. Additionally, the response may contain a list of validators,
which can be used to update the validator set. To add a new validator or
update an existing one, simply include them in the list returned in the
EndBlock response. To remove one, include it in the list with a
``power`` equal to ``0``. Tendermint core will take care of updating the
validator set. Note validator set changes are only available in v0.8.0
and up.
Query Connection
~~~~~~~~~~~~~~~~
This connection is used to query the application without engaging
consensus. It's exposed over the tendermint core rpc, so clients can
query the app without exposing a server on the app itself, but they must
serialize each query as a single byte array. Additionally, certain
"standardized" queries may be used to inform local decisions, for
instance about which peers to connect to.
Tendermint Core currently uses the Query connection to filter peers upon
connecting, according to IP address or public key. For instance,
returning non-OK ABCI response to either of the following queries will
cause Tendermint to not connect to the corresponding peer:
- ``p2p/filter/addr/<addr>``, where ``<addr>`` is an IP address.
- ``p2p/filter/pubkey/<pubkey>``, where ``<pubkey>`` is the hex-encoded
ED25519 key of the node (not it's validator key)
Note: these query formats are subject to change!
Handshake
~~~~~~~~~
When the app or tendermint restarts, they need to sync to a common
height. When an ABCI connection is first established, Tendermint will
call ``Info`` on the Query connection. The response should contain the
LastBlockHeight and LastBlockAppHash - the former is the last block for
the which the app ran Commit successfully, the latter is the response
from that Commit.
Using this information, Tendermint will determine what needs to be
replayed, if anything, against the app, to ensure both Tendermint and
the app are synced to the latest block height.
If the app returns a LastBlockHeight of 0, Tendermint will just replay
all blocks.

docs/hidden/ABCI.md → docs/architecture/ABCI.md View File


docs/hidden/README.md → docs/architecture/README.md View File


docs/hidden/adr-001.md → docs/architecture/adr-001.md View File


+ 90
- 0
docs/architecture/adr-002.md View File

@ -0,0 +1,90 @@
# ADR 2: Indexing
## Context
In the light client (or any other client), the user may want to **subscribe to
a subset of transactions** (rather than all of them) using `/subscribe?event=X`. For
example, I want to subscribe for all transactions associated with a particular
account. Same for fetching. The user may want to **fetch transactions based on
some filter** (rather than fetching all the blocks). For example, I want to get
all transactions for a particular account in the last two weeks (`tx's block
time >= '2017-06-05'`).
Now you can't even subscribe to "all txs" in Tendermint.
The goal is a simple and easy to use API for doing that.
![Tx Send Flow Diagram](img/tags1.png)
## Decision
ABCI app return tags with a `DeliverTx` response inside the `data` field (_for
now, later we may create a separate field_). Tags is a list of key-value pairs,
protobuf encoded.
Example data:
```json
{
"abci.account.name": "Igor",
"abci.account.address": "0xdeadbeef",
"tx.gas": 7
}
```
### Subscribing for transactions events
If the user wants to receive only a subset of transactions, ABCI-app must
return a list of tags with a `DeliverTx` response. These tags will be parsed and
matched with the current queries (subscribers). If the query matches the tags,
subscriber will get the transaction event.
```
/subscribe?query="tm.event = Tx AND tx.hash = AB0023433CF0334223212243BDD AND abci.account.invoice.number = 22"
```
A new package must be developed to replace the current `events` package. It
will allow clients to subscribe to a different types of events in the future:
```
/subscribe?query="abci.account.invoice.number = 22"
/subscribe?query="abci.account.invoice.owner CONTAINS Igor"
```
### Fetching transactions
This is a bit tricky because a) we want to support a number of indexers, all of
which have a different API b) we don't know whenever tags will be sufficient
for the most apps (I guess we'll see).
```
/txs/search?query="tx.hash = AB0023433CF0334223212243BDD AND abci.account.owner CONTAINS Igor"
/txs/search?query="abci.account.owner = Igor"
```
For historic queries we will need a indexing storage (Postgres, SQLite, ...).
### Issues
- https://github.com/tendermint/basecoin/issues/91
- https://github.com/tendermint/tendermint/issues/376
- https://github.com/tendermint/tendermint/issues/287
- https://github.com/tendermint/tendermint/issues/525 (related)
## Status
proposed
## Consequences
### Positive
- same format for event notifications and search APIs
- powerful enough query
### Negative
- performance of the `match` function (where we have too many queries / subscribers)
- there is an issue where there are too many txs in the DB
### Neutral

docs/hidden/adr-003.md → docs/architecture/adr-003.md View File


BIN
docs/architecture/img/tags1.png View File

Before After
Width: 990  |  Height: 440  |  Size: 10 KiB

docs/hidden/merkle-frey.md → docs/architecture/merkle-frey.md View File


docs/hidden/merkle.md → docs/architecture/merkle.md View File


BIN
docs/assets/tmint-logo-blue.png View File

Before After
Width: 2048  |  Height: 2048  |  Size: 52 KiB

+ 220
- 0
docs/block-structure.rst View File

@ -0,0 +1,220 @@
Block Structure
===============
The tendermint consensus engine records all agreements by a
supermajority of nodes into a blockchain, which is replicated among all
nodes. This blockchain is accessible via various rpc endpoints, mainly
``/block?height=`` to get the full block, as well as
``/blockchain?minHeight=_&maxHeight=_`` to get a list of headers. But
what exactly is stored in these blocks?
Block
~~~~~
A
`Block <https://godoc.org/github.com/tendermint/tendermint/types#Block>`__
contains:
- a `Header <#header>`__ contains merkle hashes for various chain
states
- the
`Data <https://godoc.org/github.com/tendermint/tendermint/types#Data>`__
is all transactions which are to be processed
- the `LastCommit <#commit>`__ > 2/3 signatures for the last block
The signatures returned along with block ``H`` are those validating
block ``H-1``. This can be a little confusing, but we must also consider
that the ``Header`` also contains the ``LastCommitHash``. It would be
impossible for a Header to include the commits that sign it, as it would
cause an infinite loop here. But when we get block ``H``, we find
``Header.LastCommitHash``, which must match the hash of ``LastCommit``.
Header
~~~~~~
The
`Header <https://godoc.org/github.com/tendermint/tendermint/types#Header>`__
contains lots of information (follow link for up-to-date info). Notably,
it maintains the ``Height``, the ``LastBlockID`` (to make it a chain),
and hashes of the data, the app state, and the validator set. This is
important as the only item that is signed by the validators is the
``Header``, and all other data must be validated against one of the
merkle hashes in the ``Header``.
The ``DataHash`` can provide a nice check on the
`Data <https://godoc.org/github.com/tendermint/tendermint/types#Data>`__
returned in this same block. If you are subscribed to new blocks, via
tendermint RPC, in order to display or process the new transactions you
should at least validate that the ``DataHash`` is valid. If it is
important to verify autheniticity, you must wait for the ``LastCommit``
from the next block to make sure the block header (including
``DataHash``) was properly signed.
The ``ValidatorHash`` contains a hash of the current
`Validators <https://godoc.org/github.com/tendermint/tendermint/types#Validator>`__.
Tracking all changes in the validator set is complex, but a client can
quickly compare this hash with the `hash of the currently known
validators <https://godoc.org/github.com/tendermint/tendermint/types#ValidatorSet.Hash>`__
to see if there have been changes.
The ``AppHash`` serves as the basis for validating any merkle proofs
that come from the `ABCI
application <https://github.com/tendermint/abci>`__. It represents the
state of the actual application, rather that the state of the blockchain
itself. This means it's necessary in order to perform any business
logic, such as verifying and account balance.
**Note** After the transactions are committed to a block, they still
need to be processed in a separate step, which happens between the
blocks. If you find a given transaction in the block at height ``H``,
the effects of running that transaction will be first visible in the
``AppHash`` from the block header at height ``H+1``.
Like the ``LastCommit`` issue, this is a requirement of the immutability
of the block chain, as the application only applies transactions *after*
they are commited to the chain.
Commit
~~~~~~
The
`Commit <https://godoc.org/github.com/tendermint/tendermint/types#Commit>`__
contains a set of
`Votes <https://godoc.org/github.com/tendermint/tendermint/types#Vote>`__
that were made by the validator set to reach consensus on this block.
This is the key to the security in any PoS system, and actually no data
that cannot be traced back to a block header with a valid set of Votes
can be trusted. Thus, getting the Commit data and verifying the votes is
extremely important.
As mentioned above, in order to find the ``precommit votes`` for block
header ``H``, we need to query block ``H+1``. Then we need to check the
votes, make sure they really are for that block, and properly formatted.
Much of this code is implemented in Go in the
`light-client <https://github.com/tendermint/light-client>`__ package.
If you look at the code, you will notice that we need to provide the
``chainID`` of the blockchain in order to properly calculate the votes.
This is to protect anyone from swapping votes between chains to fake (or
frame) a validator. Also note that this ``chainID`` is in the
``genesis.json`` from *Tendermint*, not the ``genesis.json`` from the
basecoin app (`that is a different
chainID... <https://github.com/tendermint/basecoin/issues/32>`__).
Once we have those votes, and we calculated the proper `sign
bytes <https://godoc.org/github.com/tendermint/tendermint/types#Vote.WriteSignBytes>`__
using the chainID and a `nice helper
function <https://godoc.org/github.com/tendermint/tendermint/types#SignBytes>`__,
we can verify them. The light client is responsible for maintaining a
set of validators that we trust. Each vote only stores the validators
``Address``, as well as the ``Signature``. Assuming we have a local copy
of the trusted validator set, we can look up the ``Public Key`` of the
validator given its ``Address``, then verify that the ``Signature``
matches the ``SignBytes`` and ``Public Key``. Then we sum up the total
voting power of all validators, whose votes fulfilled all these
stringent requirements. If the total number of voting power for a single
block is greater than 2/3 of all voting power, then we can finally trust
the block header, the AppHash, and the proof we got from the ABCI
application.
Vote Sign Bytes
^^^^^^^^^^^^^^^
The ``sign-bytes`` of a vote is produced by taking a
`stable-json <https://github.com/substack/json-stable-stringify>`__-like
deterministic JSON `wire <./wire-protocol.html>`__ encoding of
the vote (excluding the ``Signature`` field), and wrapping it with
``{"chain_id":"my_chain","vote":...}``.
For example, a precommit vote might have the following ``sign-bytes``:
.. code:: json
{"chain_id":"my_chain","vote":{"block_hash":"611801F57B4CE378DF1A3FFF1216656E89209A99","block_parts_header":{"hash":"B46697379DBE0774CC2C3B656083F07CA7E0F9CE","total":123},"height":1234,"round":1,"type":2}}
Block Hash
~~~~~~~~~~
The `block
hash <https://godoc.org/github.com/tendermint/tendermint/types#Block.Hash>`__
is the `Simple Tree hash <Merkle-Trees#simple-tree-with-dictionaries>`__
of the fields of the block ``Header`` encoded as a list of
``KVPair``\ s.
Transaction
~~~~~~~~~~~
A transaction is any sequence of bytes. It is up to your
`ABCI <https://github.com/tendermint/abci>`__ application to accept or
reject transactions.
BlockID
~~~~~~~
Many of these data structures refer to the
`BlockID <https://godoc.org/github.com/tendermint/tendermint/types#BlockID>`__,
which is the ``BlockHash`` (hash of the block header, also referred to
by the next block) along with the ``PartSetHeader``. The
``PartSetHeader`` is explained below and is used internally to
orchestrate the p2p propogation. For clients, it is basically opaque
bytes, but they must match for all votes.
PartSetHeader
~~~~~~~~~~~~~
The
`PartSetHeader <https://godoc.org/github.com/tendermint/tendermint/types#PartSetHeader>`__
contains the total number of pieces in a
`PartSet <https://godoc.org/github.com/tendermint/tendermint/types#PartSet>`__,
and the Merkle root hash of those pieces.
PartSet
~~~~~~~
PartSet is used to split a byteslice of data into parts (pieces) for
transmission. By splitting data into smaller parts and computing a
Merkle root hash on the list, you can verify that a part is legitimately
part of the complete data, and the part can be forwarded to other peers
before all the parts are known. In short, it's a fast way to securely
propagate a large chunk of data (like a block) over a gossip network.
PartSet was inspired by the LibSwift project.
Usage:
.. code:: go
data := RandBytes(2 << 20) // Something large
partSet := NewPartSetFromData(data)
partSet.Total() // Total number of 4KB parts
partSet.Count() // Equal to the Total, since we already have all the parts
partSet.Hash() // The Merkle root hash
partSet.BitArray() // A BitArray of partSet.Total() 1's
header := partSet.Header() // Send this to the peer
header.Total // Total number of parts
header.Hash // The merkle root hash
// Now we'll reconstruct the data from the parts
partSet2 := NewPartSetFromHeader(header)
partSet2.Total() // Same total as partSet.Total()
partSet2.Count() // Zero, since this PartSet doesn't have any parts yet.
partSet2.Hash() // Same hash as in partSet.Hash()
partSet2.BitArray() // A BitArray of partSet.Total() 0's
// In a gossip network the parts would arrive in arbitrary order, perhaps
// in response to explicit requests for parts, or optimistically in response
// to the receiving peer's partSet.BitArray().
for !partSet2.IsComplete() {
part := receivePartFromGossipNetwork()
added, err := partSet2.AddPart(part)
if err != nil {
// A wrong part,
// the merkle trail does not hash to partSet2.Hash()
} else if !added {
// A duplicate part already received
}
}
data2, _ := ioutil.ReadAll(partSet2.GetReader())
bytes.Equal(data, data2) // true

+ 349
- 0
docs/byzantine-consensus-algorithm.rst View File

@ -0,0 +1,349 @@
Byzantine Consensus Algorithm
=============================
Terms
-----
- The network is composed of optionally connected *nodes*. Nodes
directly connected to a particular node are called *peers*.
- The consensus process in deciding the next block (at some *height*
``H``) is composed of one or many *rounds*.
- ``NewHeight``, ``Propose``, ``Prevote``, ``Precommit``, and
``Commit`` represent state machine states of a round. (aka
``RoundStep`` or just "step").
- A node is said to be *at* a given height, round, and step, or at
``(H,R,S)``, or at ``(H,R)`` in short to omit the step.
- To *prevote* or *precommit* something means to broadcast a `prevote
vote <https://godoc.org/github.com/tendermint/tendermint/types#Vote>`__
or `first precommit
vote <https://godoc.org/github.com/tendermint/tendermint/types#FirstPrecommit>`__
for something.
- A vote *at* ``(H,R)`` is a vote signed with the bytes for ``H`` and
``R`` included in its
`sign-bytes <block-structure.html#vote-sign-bytes>`__.
- *+2/3* is short for "more than 2/3"
- *1/3+* is short for "1/3 or more"
- A set of +2/3 of prevotes for a particular block or ``<nil>`` at
``(H,R)`` is called a *proof-of-lock-change* or *PoLC* for short.
State Machine Overview
----------------------
At each height of the blockchain a round-based protocol is run to
determine the next block. Each round is composed of three *steps*
(``Propose``, ``Prevote``, and ``Precommit``), along with two special
steps ``Commit`` and ``NewHeight``.
In the optimal scenario, the order of steps is:
::
NewHeight -> (Propose -> Prevote -> Precommit)+ -> Commit -> NewHeight ->...
The sequence ``(Propose -> Prevote -> Precommit)`` is called a *round*.
There may be more than one round required to commit a block at a given
height. Examples for why more rounds may be required include:
- The designated proposer was not online.
- The block proposed by the designated proposer was not valid.
- The block proposed by the designated proposer did not propagate in
time.
- The block proposed was valid, but +2/3 of prevotes for the proposed
block were not received in time for enough validator nodes by the
time they reached the ``Precommit`` step. Even though +2/3 of
prevotes are necessary to progress to the next step, at least one
validator may have voted ``<nil>`` or maliciously voted for something
else.
- The block proposed was valid, and +2/3 of prevotes were received for
enough nodes, but +2/3 of precommits for the proposed block were not
received for enough validator nodes.
Some of these problems are resolved by moving onto the next round &
proposer. Others are resolved by increasing certain round timeout
parameters over each successive round.
State Machine Diagram
---------------------
::
+-------------------------------------+
v |(Wait til `CommmitTime+timeoutCommit`)
+-----------+ +-----+-----+
+----------> | Propose +--------------+ | NewHeight |
| +-----------+ | +-----------+
| | ^
|(Else, after timeoutPrecommit) v |
+-----+-----+ +-----------+ |
| Precommit | <------------------------+ Prevote | |
+-----+-----+ +-----------+ |
|(When +2/3 Precommits for block found) |
v |
+--------------------------------------------------------------------+
| Commit |
| |
| * Set CommitTime = now; |
| * Wait for block, then stage/save/commit block; |
+--------------------------------------------------------------------+
Background Gossip
-----------------
A node may not have a corresponding validator private key, but it
nevertheless plays an active role in the consensus process by relaying
relevant meta-data, proposals, blocks, and votes to its peers. A node
that has the private keys of an active validator and is engaged in
signing votes is called a *validator-node*. All nodes (not just
validator-nodes) have an associated state (the current height, round,
and step) and work to make progress.
Between two nodes there exists a ``Connection``, and multiplexed on top
of this connection are fairly throttled ``Channel``\ s of information.
An epidemic gossip protocol is implemented among some of these channels
to bring peers up to speed on the most recent state of consensus. For
example,
- Nodes gossip ``PartSet`` parts of the current round's proposer's
proposed block. A LibSwift inspired algorithm is used to quickly
broadcast blocks across the gossip network.
- Nodes gossip prevote/precommit votes. A node NODE\_A that is ahead of
NODE\_B can send NODE\_B prevotes or precommits for NODE\_B's current
(or future) round to enable it to progress forward.
- Nodes gossip prevotes for the proposed PoLC (proof-of-lock-change)
round if one is proposed.
- Nodes gossip to nodes lagging in blockchain height with block
`commits <https://godoc.org/github.com/tendermint/tendermint/types#Commit>`__
for older blocks.
- Nodes opportunistically gossip ``HasVote`` messages to hint peers
what votes it already has.
- Nodes broadcast their current state to all neighboring peers. (but is
not gossiped further)
There's more, but let's not get ahead of ourselves here.
Proposals
---------
A proposal is signed and published by the designated proposer at each
round. The proposer is chosen by a deterministic and non-choking round
robin selection algorithm that selects proposers in proportion to their
voting power. (see
`implementation <https://github.com/tendermint/tendermint/blob/develop/types/validator_set.go>`__)
A proposal at ``(H,R)`` is composed of a block and an optional latest
``PoLC-Round < R`` which is included iff the proposer knows of one. This
hints the network to allow nodes to unlock (when safe) to ensure the
liveness property.
State Machine Spec
------------------
Propose Step (height:H,round:R)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Upon entering ``Propose``: - The designated proposer proposes a block at
``(H,R)``.
The ``Propose`` step ends: - After ``timeoutProposeR`` after entering
``Propose``. --> goto ``Prevote(H,R)`` - After receiving proposal block
and all prevotes at ``PoLC-Round``. --> goto ``Prevote(H,R)`` - After
`common exit conditions <#common-exit-conditions>`__
Prevote Step (height:H,round:R)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Upon entering ``Prevote``, each validator broadcasts its prevote vote.
- First, if the validator is locked on a block since ``LastLockRound``
but now has a PoLC for something else at round ``PoLC-Round`` where
``LastLockRound < PoLC-Round < R``, then it unlocks.
- If the validator is still locked on a block, it prevotes that.
- Else, if the proposed block from ``Propose(H,R)`` is good, it
prevotes that.
- Else, if the proposal is invalid or wasn't received on time, it
prevotes ``<nil>``.
The ``Prevote`` step ends: - After +2/3 prevotes for a particular block
or ``<nil>``. --> goto ``Precommit(H,R)`` - After ``timeoutPrevote``
after receiving any +2/3 prevotes. --> goto ``Precommit(H,R)`` - After
`common exit conditions <#common-exit-conditions>`__
Precommit Step (height:H,round:R)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Upon entering ``Precommit``, each validator broadcasts its precommit
vote. - If the validator has a PoLC at ``(H,R)`` for a particular block
``B``, it (re)locks (or changes lock to) and precommits ``B`` and sets
``LastLockRound = R``. - Else, if the validator has a PoLC at ``(H,R)``
for ``<nil>``, it unlocks and precommits ``<nil>``. - Else, it keeps the
lock unchanged and precommits ``<nil>``.
A precommit for ``<nil>`` means "I didn’t see a PoLC for this round, but
I did get +2/3 prevotes and waited a bit".
The Precommit step ends: - After +2/3 precommits for ``<nil>``. --> goto
``Propose(H,R+1)`` - After ``timeoutPrecommit`` after receiving any +2/3
precommits. --> goto ``Propose(H,R+1)`` - After `common exit
conditions <#common-exit-conditions>`__
common exit conditions
^^^^^^^^^^^^^^^^^^^^^^
- After +2/3 precommits for a particular block. --> goto ``Commit(H)``
- After any +2/3 prevotes received at ``(H,R+x)``. --> goto
``Prevote(H,R+x)``
- After any +2/3 precommits received at ``(H,R+x)``. --> goto
``Precommit(H,R+x)``
Commit Step (height:H)
~~~~~~~~~~~~~~~~~~~~~~
- Set ``CommitTime = now()``
- Wait until block is received. --> goto ``NewHeight(H+1)``
NewHeight Step (height:H)
~~~~~~~~~~~~~~~~~~~~~~~~~
- Move ``Precommits`` to ``LastCommit`` and increment height.
- Set ``StartTime = CommitTime+timeoutCommit``
- Wait until ``StartTime`` to receive straggler commits. --> goto
``Propose(H,0)``
Proofs
------
Proof of Safety
~~~~~~~~~~~~~~~
Assume that at most -1/3 of the voting power of validators is byzantine.
If a validator commits block ``B`` at round ``R``, it's because it saw
+2/3 of precommits at round ``R``. This implies that 1/3+ of honest
nodes are still locked at round ``R' > R``. These locked validators will
remain locked until they see a PoLC at ``R' > R``, but this won't happen
because 1/3+ are locked and honest, so at most -2/3 are available to
vote for anything other than ``B``.
Proof of Liveness
~~~~~~~~~~~~~~~~~
If 1/3+ honest validators are locked on two different blocks from
different rounds, a proposers' ``PoLC-Round`` will eventually cause
nodes locked from the earlier round to unlock. Eventually, the
designated proposer will be one that is aware of a PoLC at the later
round. Also, ``timeoutProposalR`` increments with round ``R``, while the
size of a proposal are capped, so eventually the network is able to
"fully gossip" the whole proposal (e.g. the block & PoLC).
Proof of Fork Accountability
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Define the JSet (justification-vote-set) at height ``H`` of a validator
``V1`` to be all the votes signed by the validator at ``H`` along with
justification PoLC prevotes for each lock change. For example, if ``V1``
signed the following precommits: ``Precommit(B1 @ round 0)``,
``Precommit(<nil> @ round 1)``, ``Precommit(B2 @ round 4)`` (note that
no precommits were signed for rounds 2 and 3, and that's ok),
``Precommit(B1 @ round 0)`` must be justified by a PoLC at round 0, and
``Precommit(B2 @ round 4)`` must be justified by a PoLC at round 4; but
the precommit for ``<nil>`` at round 1 is not a lock-change by
definition so the JSet for ``V1`` need not include any prevotes at round
1, 2, or 3 (unless ``V1`` happened to have prevoted for those rounds).
Further, define the JSet at height ``H`` of a set of validators ``VSet``
to be the union of the JSets for each validator in ``VSet``. For a given
commit by honest validators at round ``R`` for block ``B`` we can
construct a JSet to justify the commit for ``B`` at ``R``. We say that a
JSet *justifies* a commit at ``(H,R)`` if all the committers (validators
in the commit-set) are each justified in the JSet with no duplicitous
vote signatures (by the committers).
- **Lemma**: When a fork is detected by the existence of two
conflicting `commits <./validators.html#commiting-a-block>`__,
the union of the JSets for both commits (if they can be compiled)
must include double-signing by at least 1/3+ of the validator set.
**Proof**: The commit cannot be at the same round, because that would
immediately imply double-signing by 1/3+. Take the union of the JSets
of both commits. If there is no double-signing by at least 1/3+ of
the validator set in the union, then no honest validator could have
precommitted any different block after the first commit. Yet, +2/3
did. Reductio ad absurdum.
As a corollary, when there is a fork, an external process can determine
the blame by requiring each validator to justify all of its round votes.
Either we will find 1/3+ who cannot justify at least one of their votes,
and/or, we will find 1/3+ who had double-signed.
Alternative algorithm
~~~~~~~~~~~~~~~~~~~~~
Alternatively, we can take the JSet of a commit to be the "full commit".
That is, if light clients and validators do not consider a block to be
committed unless the JSet of the commit is also known, then we get the
desirable property that if there ever is a fork (e.g. there are two
conflicting "full commits"), then 1/3+ of the validators are immediately
punishable for double-signing.
There are many ways to ensure that the gossip network efficiently share
the JSet of a commit. One solution is to add a new message type that
tells peers that this node has (or does not have) a +2/3 majority for B
(or ) at (H,R), and a bitarray of which votes contributed towards that
majority. Peers can react by responding with appropriate votes.
We will implement such an algorithm for the next iteration of the
Tendermint consensus protocol.
Other potential improvements include adding more data in votes such as
the last known PoLC round that caused a lock change, and the last voted
round/step (or, we may require that validators not skip any votes). This
may make JSet verification/gossip logic easier to implement.
Censorship Attacks
~~~~~~~~~~~~~~~~~~
Due to the definition of a block
`commit <validators.html#commiting-a-block>`__, any 1/3+
coalition of validators can halt the blockchain by not broadcasting
their votes. Such a coalition can also censor particular transactions by
rejecting blocks that include these transactions, though this would
result in a significant proportion of block proposals to be rejected,
which would slow down the rate of block commits of the blockchain,
reducing its utility and value. The malicious coalition might also
broadcast votes in a trickle so as to grind blockchain block commits to
a near halt, or engage in any combination of these attacks.
If a global active adversary were also involved, it can partition the
network in such a way that it may appear that the wrong subset of
validators were responsible for the slowdown. This is not just a
limitation of Tendermint, but rather a limitation of all consensus
protocols whose network is potentially controlled by an active
adversary.
Overcoming Forks and Censorship Attacks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For these types of attacks, a subset of the validators through external
means should coordinate to sign a reorg-proposal that chooses a fork
(and any evidence thereof) and the initial subset of validators with
their signatures. Validators who sign such a reorg-proposal forego its
collateral on all other forks. Clients should verify the signatures on
the reorg-proposal, verify any evidence, and make a judgement or prompt
the end-user for a decision. For example, a phone wallet app may prompt
the user with a security warning, while a refrigerator may accept any
reorg-proposal signed by +½ of the original validators.
No non-synchronous Byzantine fault-tolerant algorithm can come to
consensus when ⅓+ of validators are dishonest, yet a fork assumes that
⅓+ of validators have already been dishonest by double-signing or
lock-changing without justification. So, signing the reorg-proposal is a
coordination problem that cannot be solved by any non-synchronous
protocol (i.e. automatically, and without making assumptions about the
reliability of the underlying network). It must be provided by means
external to the weakly-synchronous Tendermint consensus algorithm. For
now, we leave the problem of reorg-proposal coordination to human
coordination via internet media. Validators must take care to ensure
that there are no significant network partitions, to avoid situations
where two conflicting reorg-proposals are signed.
Assuming that the external coordination medium and protocol is robust,
it follows that forks are less of a concern than `censorship
attacks <#censorship-attacks>`__.

+ 171
- 0
docs/conf.py View File

@ -0,0 +1,171 @@
# -*- coding: utf-8 -*-
#
# Tendermint documentation build configuration file, created by
# sphinx-quickstart on Mon Aug 7 04:55:09 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import sphinx_rtd_theme
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_suffix = ['.rst', '.md']
# source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Tendermint'
copyright = u'2017, The Authors'
author = u'Tendermint'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u''
# The full version, including alpha/beta/rc tags.
release = u''
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'architecture']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
'donate.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'Tendermintdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'Tendermint.tex', u'Tendermint Documentation',
u'The Authors', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'Tendermint', u'Tendermint Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'Tendermint', u'Tendermint Documentation',
author, 'Tendermint', 'Byzantine Fault Tolerant Consensus.',
'Database'),
]

+ 55
- 0
docs/configuration.rst View File

@ -0,0 +1,55 @@
Configuration
=============
TendermintCore can be configured via a TOML file in
``$TMHOME/config.toml``. Some of these parameters can be overridden by
command-line flags.
Config parameters
~~~~~~~~~~~~~~~~~
The main config parameters are defined
`here <https://github.com/tendermint/tendermint/blob/master/config/config.go>`__.
- ``abci``: ABCI transport (socket \| grpc). *Default*: ``socket``
- ``db_backend``: Database backend for the blockchain and
TendermintCore state. ``leveldb`` or ``memdb``. *Default*:
``"leveldb"``
- ``db_dir``: Database dir. *Default*: ``"$TMHOME/data"``
- ``fast_sync``: Whether to sync faster from the block pool. *Default*:
``true``
- ``genesis_file``: The location of the genesis file. *Default*:
``"$TMHOME/genesis.json"``
- ``log_level``: *Default*: ``"state:info,*:error"``
- ``moniker``: Name of this node. *Default*: ``"anonymous"``
- ``priv_validator_file``: Validator private key file. *Default*:
``"$TMHOME/priv_validator.json"``
- ``prof_laddr``: Profile listen address. *Default*: ``""``
- ``proxy_app``: The ABCI app endpoint. *Default*:
``"tcp://127.0.0.1:46658"``
- ``consensus.max_block_size_txs``: Maximum number of block txs.
*Default*: ``10000``
- ``consensus.timeout_*``: Various consensus timeout parameters
**TODO**
- ``consensus.wal_file``: Consensus state WAL. *Default*:
``"$TMHOME/data/cswal"``
- ``consensus.wal_light``: Whether to use light-mode for Consensus
state WAL. *Default*: ``false``
- ``mempool.*``: Various mempool parameters **TODO**
- ``p2p.addr_book_file``: Peer address book. *Default*:
``"$TMHOME/addrbook.json"``. **NOT USED**
- ``p2p.laddr``: Node listen address. (0.0.0.0:0 means any interface,
any port). *Default*: ``"0.0.0.0:46656"``
- ``p2p.pex``: Enable Peer-Exchange (dev feature). *Default*: ``false``
- ``p2p.seeds``: Comma delimited host:port seed nodes. *Default*:
``""``
- ``p2p.skip_upnp``: Skip UPNP detection. *Default*: ``false``
- ``rpc.grpc_laddr``: GRPC listen address (BroadcastTx only). Port
required. *Default*: ``""``
- ``rpc.laddr``: RPC listen address. Port required. *Default*:
``"0.0.0.0:46657"``
- ``rpc.unsafe``: Enabled unsafe rpc methods. *Default*: ``true``

+ 47
- 0
docs/deploy-testnets.rst View File

@ -0,0 +1,47 @@
Deploy a Testnet
================
Now that we've seen how ABCI works, and even played with a few
applications on a single validator node, it's time to deploy a test
network to four validator nodes. For this deployment, we'll use the
``basecoin`` application.
Manual Deployments
------------------
It's relatively easy to setup a Tendermint cluster manually. The only
requirements for a particular Tendermint node are a private key for the
validator, stored as ``priv_validator.json``, and a list of the public
keys of all validators, stored as ``genesis.json``. These files should
be stored in ``~/.tendermint``, or wherever the ``$TMROOT`` variable
might be set to.
Here are the steps to setting up a testnet manually:
1) Provision nodes on your cloud provider of choice
2) Install Tendermint and the application of interest on all nodes
3) Generate a private key for each validator using
``tendermint gen_validator``
4) Compile a list of public keys for each validator into a
``genesis.json`` file.
5) Run ``tendermint node --p2p.seeds=< seed addresses >`` on each node,
where ``< seed addresses >`` is a comma separated list of the IP:PORT
combination for each node. The default port for Tendermint is
``46656``. Thus, if the IP addresses of your nodes were
``192.168.0.1, 192.168.0.2, 192.168.0.3, 192.168.0.4``, the command
would look like:
``tendermint node --p2p.seeds=192.168.0.1:46656,192.168.0.2:46656,192.168.0.3:46656,192.168.0.4:46656``.
After a few seconds, all the nodes should connect to eachother and start
making blocks! For more information, see the Tendermint Networks section
of `the guide to using Tendermint <using-tendermint.html>`__.
Automated Deployments
---------------------
While the manual deployment is easy enough, an automated deployment is
always better. For this, we have the `mintnet-kubernetes
tool <https://github.com/tendermint/tools/tree/master/mintnet-kubernetes>`__,
which allows us to automate the deployment of a Tendermint network on an
already provisioned kubernetes cluster. And for simple provisioning of kubernetes
cluster, check out the `Google Cloud Platform <https://cloud.google.com/>`__.

+ 34
- 0
docs/fast-sync.rst View File

@ -0,0 +1,34 @@
Fast Sync
=========
Background
----------
In a proof of work blockchain, syncing with the chain is the same
process as staying up-to-date with the consensus: download blocks, and
look for the one with the most total work. In proof-of-stake, the
consensus process is more complex, as it involves rounds of
communication between the nodes to determine what block should be
committed next. Using this process to sync up with the blockchain from
scratch can take a very long time. It's much faster to just download
blocks and check the merkle tree of validators than to run the real-time
consensus gossip protocol.
Fast Sync
---------
To support faster syncing, tendermint offers a ``fast-sync`` mode, which
is enabled by default, and can be toggled in the ``config.toml`` or via
``--fast_sync=false``.
In this mode, the tendermint daemon will sync hundreds of times faster
than if it used the real-time consensus process. Once caught up, the
daemon will switch out of fast sync and into the normal consensus mode.
After running for some time, the node is considered ``caught up`` if it
has at least one peer and it's height is at least as high as the max
reported peer height. See `the IsCaughtUp
method <https://github.com/tendermint/tendermint/blob/b467515719e686e4678e6da4e102f32a491b85a0/blockchain/pool.go#L128>`__.
If we're lagging sufficiently, we should go back to fast syncing, but
this is an open issue:
https://github.com/tendermint/tendermint/issues/129

+ 73
- 0
docs/genesis.rst View File

@ -0,0 +1,73 @@
Genesis
=======
The genesis.json file in ``$TMROOT`` defines the initial TendermintCore
state upon genesis of the blockchain (`see
definition <https://github.com/tendermint/tendermint/blob/master/types/genesis.go>`__).
NOTE: This does not (yet) specify the application state (e.g. initial
distribution of tokens). Currently we leave it up to the application to
load the initial application genesis state. In the future, we may
include genesis SetOption messages that get passed from TendermintCore
to the app upon genesis.
Fields
~~~~~~
- ``genesis_time``: Official time of blockchain start.
- ``chain_id``: ID of the blockchain. This must be unique for every
blockchain. If your testnet blockchains do not have unique chain IDs,
you will have a bad time.
- ``validators``:
- ``pub_key``: The first element specifies the pub\_key type. 1 ==
Ed25519. The second element are the pubkey bytes.
- ``amount``: The validator's voting power.
- ``name``: Name of the validator (optional).
- ``app_hash``: The expected application hash (as returned by the
``Commit`` ABCI message) upon genesis. If the app's hash does not
match, a warning message is printed.
Sample genesis.json
~~~~~~~~~~~~~~~~~~~
.. code:: json
{
"genesis_time": "2016-02-05T06:02:31.526Z",
"chain_id": "chain-tTH4mi",
"validators": [
{
"pub_key": [
1,
"9BC5112CB9614D91CE423FA8744885126CD9D08D9FC9D1F42E552D662BAA411E"
],
"amount": 1,
"name": "mach1"
},
{
"pub_key": [
1,
"F46A5543D51F31660D9F59653B4F96061A740FF7433E0DC1ECBC30BE8494DE06"
],
"amount": 1,
"name": "mach2"
},
{
"pub_key": [
1,
"0E7B423C1635FD07C0FC3603B736D5D27953C1C6CA865BB9392CD79DE1A682BB"
],
"amount": 1,
"name": "mach3"
},
{
"pub_key": [
1,
"4F49237B9A32EB50682EDD83C48CE9CDB1D02A7CFDADCFF6EC8C1FAADB358879"
],
"amount": 1,
"name": "mach4"
}
],
"app_hash": "15005165891224E721CB664D15CB972240F5703F"
}

+ 277
- 0
docs/getting-started.rst View File

@ -0,0 +1,277 @@
First Tendermint App
====================
As a general purpose blockchain engine, Tendermint is agnostic to the
application you want to run. So, to run a complete blockchain that does
something useful, you must start two programs: one is Tendermint Core,
the other is your application, which can be written in any programming
language. Recall from `the intro to ABCI <introduction.rst#ABCI-Overview>`__ that
Tendermint Core handles all the p2p and consensus stuff, and just
forwards transactions to the application when they need to be validated,
or when they're ready to be committed to a block.
In this guide, we show you some examples of how to run an application
using Tendermint.
Install
-------
The first apps we will work with are written in Go. To install them, you
need to `install Go <https://golang.org/doc/install>`__ and put
``$GOPATH/bin`` in your
``$PATH``; see `here <https://github.com/tendermint/tendermint/wiki/Setting-GOPATH>`__ for more info.
Then run
::
go get -u github.com/tendermint/abci/cmd/...
If there is an error, install and run the ``glide`` tool to pin the
dependencies:
::
go get github.com/Masterminds/glide
cd $GOPATH/src/github.com/tendermint/abci
glide install
go install ./cmd/...
Now you should have the ``abci-cli`` plus two apps installed:
::
dummy --help
counter --help
These binaries are installed on ``$GOPATH/bin`` and all come from within
the ``./cmd/...`` directory of the abci repository.
Both of these example applications are in Go. See below for an
application written in Javascript.
Now, let's run some apps!
Dummy - A First Example
-----------------------
The dummy app is a `Merkle
tree <https://en.wikipedia.org/wiki/Merkle_tree>`__ that just stores all
transactions. If the transaction contains an ``=``, eg. ``key=value``,
then the ``value`` is stored under the ``key`` in the Merkle tree.
Otherwise, the full transaction bytes are stored as the key and the
value.
Let's start a dummy application.
::
dummy
In another terminal, we can start Tendermint. If you have never run
Tendermint before, use:
::
tendermint init
tendermint node
If you have used Tendermint, you may want to reset the data for a new
blockchain by running ``tendermint unsafe_reset_all``. Then you can run
``tendermint node`` to start Tendermint, and connect to the app. For
more details, see `the guide on using
Tendermint <./using-tendermint.html>`__.
You should see Tendermint making blocks! We can get the status of our
Tendermint node as follows:
::
curl -s localhost:46657/status
The ``-s`` just silences ``curl``. For nicer output, pipe the result
into a tool like `jq <https://stedolan.github.io/jq/>`__ or
`jsonpp <https://github.com/jmhodges/jsonpp>`__.
Now let's send some transactions to the dummy.
::
curl -s 'localhost:46657/broadcast_tx_commit?tx="abcd"'
Note the single quote (``'``) around the url, which ensures that the
double quotes (``"``) are not escaped by bash. This command sent a
transaction with bytes ``abcd``, so ``abcd`` will be stored as both the
key and the value in the Merkle tree. The response should look something
like:
::
{"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{}}],"error":""}
The ``98`` is a type-byte, and can be ignored (it's useful for
serializing and deserializing arbitrary json). Otherwise, this result is
empty - there's nothing to report on and everything is OK.
We can confirm that our transaction worked and the value got stored by
querying the app:
::
curl -s 'localhost:46657/abci_query?data="abcd"&path=""&prove=false'
The ``path`` and ``prove`` arguments can be ignored for now, and in a
future release can be left out. The result should look like:
::
{"jsonrpc":"2.0","id":"","result":[112,{"response":{"value":"61626364","log":"exists"}}],"error":""}
Again, the ``112`` is the type-byte. Note the ``value`` in the result
(``61626364``); this is the hex-encoding of the ASCII of ``abcd``. You
can verify this in a python shell by running
``"61626364".decode('hex')``. Stay tuned for a future release that makes
this output more human-readable ;).
Now let's try setting a different key and value:
::
curl -s 'localhost:46657/broadcast_tx_commit?tx="name=satoshi"'
Now if we query for ``name``, we should get ``satoshi``, or
``7361746F736869`` in hex:
::
curl -s 'localhost:46657/abci_query?data="name"&path=""&prove=false'
Try some other transactions and queries to make sure everything is
working!
Counter - Another Example
-------------------------
Now that we've got the hang of it, let's try another application, the
"counter" app.
The counter app doesn't use a Merkle tree, it just counts how many times
we've sent a transaction, or committed the state.
This application has two modes: ``serial=off`` and ``serial=on``.
When ``serial=on``, transactions must be a big-endian encoded
incrementing integer, starting at 0.
If ``serial=off``, there are no restrictions on transactions.
In a live blockchain, transactions collect in memory before they are
committed into blocks. To avoid wasting resources on invalid
transactions, ABCI provides the ``CheckTx`` message, which application
developers can use to accept or reject transactions, before they are
stored in memory or gossipped to other peers.
In this instance of the counter app, with ``serial=on``, ``CheckTx``
only allows transactions whose integer is greater than the last
committed one.
Let's kill the previous instance of ``tendermint`` and the ``dummy``
application, and start the counter app. We can enable ``serial=on`` with
a flag:
::
counter --serial
In another window, reset then start Tendermint:
::
tendermint unsafe_reset_all
tendermint node
Once again, you can see the blocks streaming by. Let's send some
transactions. Since we have set ``serial=on``, the first transaction
must be the number ``0``:
::
curl localhost:46657/broadcast_tx_commit?tx=0x00
Note the empty (hence successful) response. The next transaction must be
the number ``1``. If instead, we try to send a ``5``, we get an error:
::
> curl localhost:46657/broadcast_tx_commit?tx=0x05
{"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{"code":3,"log":"Invalid nonce. Expected 1, got 5"}}],"error":""}
But if we send a ``1``, it works again:
::
> curl localhost:46657/broadcast_tx_commit?tx=0x01
{"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{}}],"error":""}
For more details on the ``broadcast_tx`` API, see `the guide on using
Tendermint <./using-tendermint.html>`__.
CounterJS - Example in Another Language
---------------------------------------
We also want to run applications in another language - in this case,
we'll run a Javascript version of the ``counter``. To run it, you'll
need to `install node <https://nodejs.org/en/download/>`__.
You'll also need to fetch the relevant repository, from `here <https://github.com/tendermint/js-abci>`__ then install it. As go devs, we
keep all our code under the ``$GOPATH``, so run:
::
go get github.com/tendermint/js-abci &> /dev/null
cd $GOPATH/src/github.com/tendermint/js-abci/example
npm install
Kill the previous ``counter`` and ``tendermint`` processes. Now run the
app:
::
node example/app.js
In another window, reset and start ``tendermint``:
::
tendermint unsafe_reset_all
tendermint node
Once again, you should see blocks streaming by - but now, our
application is written in javascript! Try sending some transactions, and
like before - the results should be the same:
::
curl localhost:46657/broadcast_tx_commit?tx=0x00 # ok
curl localhost:46657/broadcast_tx_commit?tx=0x05 # invalid nonce
curl localhost:46657/broadcast_tx_commit?tx=0x01 # ok
Neat, eh?
Basecoin - A More Interesting Example
-------------------------------------
We saved the best for last; the `Cosmos SDK <https://github.com/cosmos/cosmos-sdk>`__ is a general purpose framework for building cryptocurrencies. Unlike the``dummy`` and ``counter``, which are strictly for example purposes. The reference implementation of Cosmos SDK is ``basecoin``, which demonstrates how to use the building blocks of the Cosmos SDK.
The default ``basecoin`` application is a multi-asset cryptocurrency
that supports inter-blockchain communication. For more details on how
basecoin works and how to use it, see our `basecoin
guide <https://github.com/cosmos/cosmos-sdk/blob/develop/docs/guide/basecoin-basics.md>`__
In this tutorial you learned how to run applications using Tendermint
on a single node. You saw how applications could be written in different
languages, and how to send transactions and query for the latest state.
But the true power of Tendermint comes from its ability to securely and
efficiently run an application across a distributed network of nodes,
while keeping them all in sync using its state-of-the-art consensus
protocol. Next, we show you how to deploy Tendermint testnets.

+ 0
- 246
docs/getting-started/#02-first-app.md View File

@ -1,246 +0,0 @@
# First Tendermint App
As a general purpose blockchain engine, Tendermint is agnostic to the application you want to run.
So, to run a complete blockchain that does something useful, you must start two programs:
one is Tendermint Core, the other is your application, which can be written in any programming language.
Recall from [the intro to ABCI](/intro/abci-overview) that Tendermint Core handles all the p2p and consensus stuff,
and just forwards transactions to the application when they need to be validated, or when they're ready to be committed to a block.
In this guide, we show you some examples of how to run an application using Tendermint.
**Note:** It is highly recommended to read the [Using Tendermint Guide](/docs/guides/using-tendermint) prior to working through this tutorial.
## Install
First, make sure you have [installed Tendermint](/download).
The first apps we will work with are written in Go.
To install them, you need to [install Go](https://golang.org/doc/install) and
[put `$GOPATH/bin` in your `$PATH`](https://github.com/tendermint/tendermint/wiki/Setting-GOPATH).
Then run
```
go get -u github.com/tendermint/abci/cmd/...
```
If there is an error, install and run the `glide` tool to pin the dependencies:
```
go get github.com/Masterminds/glide
cd $GOPATH/src/github.com/tendermint/abci
glide install
go install ./cmd/...
```
Now you should have the `abci-cli` plus two apps installed:
```
dummy --help
counter --help
```
These binaries are installed on `$GOPATH/bin` and all come from within the `./cmd/...` directory of the abci repository.
Both of these example applications are in Go. See below for an application written in Javascript.
Now, let's run some apps!
## A First Example - Dummy
The dummy app is a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) that just stores all transactions.
If the transaction contains an `=`, eg. `key=value`,
then the `value` is stored under the `key` in the Merkle tree.
Otherwise, the full transaction bytes are stored as the key and the value.
Let's start a dummy application.
```
dummy
```
In another terminal, we can start Tendermint.
If you have never run Tendermint before, use:
```
tendermint init
tendermint node
```
If you have used Tendermint, you may want to reset the data for a new blockchain by running `tendermint unsafe_reset_all`.
Then you can run `tendermint node` to start Tendermint, and connect to the app.
For more details, see [the guide on using Tendermint](/docs/guides/using-tendermint).
You should see Tendermint making blocks!
We can get the status of our Tendermint node as follows:
```
curl -s localhost:46657/status
```
The `-s` just silences `curl`. For nicer output, pipe the result into a tool like [jq](https://stedolan.github.io/jq/)
or [jsonpp](https://github.com/jmhodges/jsonpp).
Now let's send some transactions to the dummy.
```
curl -s 'localhost:46657/broadcast_tx_commit?tx="abcd"'
```
Note the single quote (`'`) around the url, which ensures that the double quotes (`"`) are not escaped by bash.
This command sent a transaction with bytes `abcd`, so `abcd` will be stored as both the key and the value in the Merkle tree.
The response should look something like:
```
{"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{}}],"error":""}
```
The `98` is a type-byte, and can be ignored (it's useful for serializing and deserializing arbitrary json).
Otherwise, this result is empty - there's nothing to report on and everything is OK.
We can confirm that our transaction worked and the value got stored by querying the app:
```
curl -s 'localhost:46657/abci_query?data="abcd"&path=""&prove=false'
```
The `path` and `prove` arguments can be ignored for now, and in a future release can be left out.
The result should look like:
```
{"jsonrpc":"2.0","id":"","result":[112,{"response":{"value":"61626364","log":"exists"}}],"error":""}
```
Again, the `112` is the type-byte. Note the `value` in the result (`61626364`); this is the hex-encoding of the ASCII of `abcd`.
You can verify this in a python shell by running `"61626364".decode('hex')`.
Stay tuned for a future release that makes this output more human-readable ;).
Now let's try setting a different key and value:
```
curl -s 'localhost:46657/broadcast_tx_commit?tx="name=satoshi"'
```
Now if we query for `name`, we should get `satoshi`, or `7361746F736869` in hex:
```
curl -s 'localhost:46657/abci_query?data="name"&path=""&prove=false'
```
Try some other transactions and queries to make sure everything is working!
## Another Example - Counter
Now that we've got the hang of it, let's try another application, the "counter" app.
The counter app doesn't use a Merkle tree, it just counts how many times we've sent a transaction,
or committed the state.
This application has two modes: `serial=off` and `serial=on`.
When `serial=on`, transactions must be a big-endian encoded incrementing integer, starting at 0.
If `serial=off`, there are no restrictions on transactions.
In a live blockchain, transactions collect in memory before they are committed into blocks.
To avoid wasting resources on invalid transactions,
ABCI provides the `CheckTx` message,
which application developers can use to accept or reject transactions,
before they are stored in memory or gossipped to other peers.
In this instance of the counter app, with `serial=on`, `CheckTx` only allows transactions whose integer is greater than the last committed one.
Let's kill the previous instance of `tendermint` and the `dummy` application, and start the counter app.
We can enable `serial=on` with a flag:
```
counter --serial
```
In another window, reset then start Tendermint:
```
tendermint unsafe_reset_all
tendermint node
```
Once again, you can see the blocks streaming by. Let's send some transactions.
Since we have set `serial=on`, the first transaction must be the number `0`:
```
curl localhost:46657/broadcast_tx_commit?tx=0x00
```
Note the empty (hence successful) response.
The next transaction must be the number `1`. If instead, we try to send a `5`, we get an error:
```
> curl localhost:46657/broadcast_tx_commit?tx=0x05
{"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{"code":3,"log":"Invalid nonce. Expected 1, got 5"}}],"error":""}
```
But if we send a `1`, it works again:
```
> curl localhost:46657/broadcast_tx_commit?tx=0x01
{"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{}}],"error":""}
```
For more details on the `broadcast_tx` API,
see [the guide on using Tendermint](/docs/guides/using-tendermint).
## Example in Another Language - CounterJS
We also want to run applications in another language - in this case, we'll run a Javascript version of the `counter`.
To run it, you'll need to [install node](https://nodejs.org/en/download/).
You'll also need to fetch the relevant repository, from https://github.com/tendermint/js-abci then install it.
As go devs, we keep all our code under the `$GOPATH`, so run:
```
go get github.com/tendermint/js-abci &> /dev/null
cd $GOPATH/src/github.com/tendermint/js-abci/example
npm install
```
Kill the previous `counter` and `tendermint` processes. Now run the app:
```
node example/app.js
```
In another window, reset and start `tendermint`:
```
tendermint unsafe_reset_all
tendermint node
```
Once again, you should see blocks streaming by - but now, our application is written in javascript!
Try sending some transactions, and like before - the results should be the same:
```
curl localhost:46657/broadcast_tx_commit?tx=0x00 # ok
curl localhost:46657/broadcast_tx_commit?tx=0x05 # invalid nonce
curl localhost:46657/broadcast_tx_commit?tx=0x01 # ok
```
Neat, eh?
## A More Interesting Example - Basecoin
Before concluding, we'd like to introduce you to our star application, [Basecoin](https://github.com/tendermint/basecoin).
Unlike the `dummy` and `counter`, which are strictly for example purposes,
`basecoin` is designed to be actually useful - it's a general purpose framework for building cryptocurrencies.
The default `basecoin` application is a multi-asset cryptocurrency that supports inter-blockchain communication.
For more details on how basecoin works and how to use it, see our [basecoin guide](https://github.com/tendermint/basecoin/blob/develop/docs/guide/basecoin-basics.md)
## Next Step
In this tutorial you learned how to run applications using Tendermint on a single node.
You saw how applications could be written in different languages,
and how to send transactions and query for the latest state.
But the true power of Tendermint comes from its ability to securely and efficiently run an application
across a distributed network of nodes, while keeping them all in sync using its state-of-the-art consensus protocol.
This is the subject of the next tutorial, where we show you [how to deploy Tendermint networks](/docs/getting-started/deploy-testnet).

+ 0
- 39
docs/getting-started/#03-deploy-testnet.md View File

@ -1,39 +0,0 @@
# Deploy a Testnet
Now that we've seen how ABCI works, and even played with a few applications on a single validator node,
it's time to deploy a test network to four validator nodes.
For this deployment, we'll use the `basecoin` application.
## Manual Deployments
It's relatively easy to setup a Tendermint cluster manually.
The only requirements for a particular Tendermint node are a private key for the validator,
stored as `priv_validator.json`, and a list of the public keys of all validators, stored as `genesis.json`.
These files should be stored in `~/.tendermint`, or wherever the `$TMROOT` variable might be set to.
Here are the steps to setting up a testnet manually:
1) Provision nodes on your cloud provider of choice
2) Install Tendermint and the application of interest on all nodes
3) Generate a private key for each validator using `tendermint gen_validator`
4) Compile a list of public keys for each validator into a `genesis.json` file.
5) Run `tendermint node --p2p.seeds=< seed addresses >` on each node, where `< seed addresses >` is a
comma separated list of the IP:PORT combination for each node. The default port for Tendermint is `46656`.
Thus, if the IP addresses of your nodes were `192.168.0.1, 192.168.0.2, 192.168.0.3, 192.168.0.4`,
the command would look like: `tendermint node --p2p.seeds=192.168.0.1:46656,192.168.0.2:46656,192.168.0.3:46656,192.168.0.4:46656`.
After a few seconds, all the nodes should connect to eachother and start making blocks!
For more information, see the Tendermint Networks section of [the guide to using Tendermint](/docs/guides/using-tendermint).
## Automated Deployments
While the manual deployment is easy enough, an automated deployment is always better.
For this, we have the [mintnet-kubernetes tool](https://github.com/tendermint/tools/tree/master/mintnet-kubernetes),
which allows us to automate the deployment of a Tendermint network on an already provisioned kubernetes cluster.
For more details, see the [mintnet-kubernetes directory](https://github.com/tendermint/tools/tree/master/mintnet-kubernetes),
and check out [Google Cloud Platform](https://cloud.google.com/) for simple provisioning of kubernetes clusters.
## Next Steps
Done trying out the testnet? Continue [onwards](/docs/getting-started/next-steps).

+ 0
- 21
docs/getting-started/#04-next-steps.md View File

@ -1,21 +0,0 @@
# Next Steps
By now you've seen how to run a simple example ABCI application on a local Tendermint node
and on a remote Tendermint cluster.
To learn more about building ABCI applications and integrating with Tendermint, see the [Developer Guides](/docs/guides/app-development).
To learn more about running the Tendermint software, see the [Using Tendermint Guide](/docs/guides/using-tendermint).
To learn more about Tendermint's various pieces, check out the [Documentation](/docs).
For a deeper dive, see [this thesis](https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769).
There is also the [original whitepaper](/static/docs/tendermint.pdf), though it is now quite outdated.
The Tendermint [Software Ecosystem](/ecosystem) contains many example applications and related software built by the Tendermint team and others. Check it out for some inspiration!
For details on how the software has changed, and what changes are in store, see the [Changelog](/docs/changelog) and the [Roadmap](/docs/roadmap).
See our [Community](/community) page for more ways to collaborate.
You can also [get in touch with the team](/contact).
Most importantly, enjoy!

+ 0
- 219
docs/guides/abci-cli.md View File

@ -1,219 +0,0 @@
# Using the abci-cli
To facilitate testing and debugging of ABCI servers and simple apps,
we built a CLI, the `abci-cli`, for sending ABCI messages from the command line.
## Install
Make sure you [have Go installed](https://golang.org/doc/install) and [put `$GOPATH/bin` in your `$PATH`](https://github.com/tendermint/tendermint/wiki/Setting-GOPATH).
Next, install the `abci-cli` tool and example applications:
```
go get -u github.com/tendermint/abci/cmd/...
```
If this fails, you may need to use `glide` to get vendored dependencies:
```
go get github.com/Masterminds/glide
cd $GOPATH/src/github.com/tendermint/abci
glide install
go install ./cmd/...
```
Now run `abci-cli --help` to see the list of commands:
```
COMMANDS:
batch Run a batch of ABCI commands against an application
console Start an interactive console for multiple commands
echo Have the application echo a message
info Get some info about the application
set_option Set an option on the application
deliver_tx Append a new tx to application
check_tx Validate a tx
commit Get application Merkle root hash
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--address "tcp://127.0.0.1:46658" address of application socket
--help, -h show help
--version, -v print the version
```
## First Example - Dummy
The `abci-cli` tool lets us send ABCI messages to our application, to help build and debug them.
The most important messages are `deliver_tx`, `check_tx`, and `commit`,
but there are others for convenience, configuration, and information purposes.
Let's start a dummy application, which was installed at the same time as `abci-cli` above. The dummy just stores transactions in a merkle tree:
```
dummy
```
In another terminal, run
```
abci-cli echo hello
abci-cli info
```
The application should echo `hello` and give you some information about itself.
An ABCI application must provide two things:
- a socket server
- a handler for ABCI messages
When we run the `abci-cli` tool we open a new connection to the application's socket server,
send the given ABCI message, and wait for a response.
The server may be generic for a particular language, and we provide a [reference implementation
in Golang](https://github.com/tendermint/abci/tree/master/server).
See the [list of other ABCI implementations](https://tendermint.com/ecosystem)
for servers in other languages.
The handler is specific to the application, and may be arbitrary,
so long as it is deterministic and conforms to the ABCI interface specification.
So when we run `abci-cli info`, we open a new connection to the ABCI server, which calls the `Info()` method on the application, which tells us the number of transactions in our Merkle tree.
Now, since every command opens a new connection, we provide the `abci-cli console` and `abci-cli batch` commands,
to allow multiple ABCI messages to be sent over a single connection.
Running `abci-cli console` should drop you in an interactive console for speaking ABCI messages to your application.
Try running these commands:
```
> echo hello
-> data: hello
> info
-> data: {"size":0}
> commit
-> data: 0x
> deliver_tx "abc"
-> code: OK
> info
-> data: {"size":1}
> commit
-> data: 0x750502FC7E84BBD788ED589624F06CFA871845D1
> query "abc"
-> code: OK
-> data: {"index":0,"value":"abc","exists":true}
> deliver_tx "def=xyz"
-> code: OK
> commit
-> data: 0x76393B8A182E450286B0694C629ECB51B286EFD5
> query "def"
-> code: OK
-> data: {"index":1,"value":"xyz","exists":true}
```
Note that if we do `deliver_tx "abc"` it will store `(abc, abc)`,
but if we do `deliver_tx "abc=efg"` it will store `(abc, efg)`.
Similarly, you could put the commands in a file and run `abci-cli --verbose batch < myfile`.
## Another Example - Counter
Now that we've got the hang of it, let's try another application, the "counter" app.
The counter app doesn't use a Merkle tree, it just counts how many times we've sent a transaction,
asked for a hash, or committed the state. The result of `commit` is just the number of transactions sent.
This application has two modes: `serial=off` and `serial=on`.
When `serial=on`, transactions must be a big-endian encoded incrementing integer, starting at 0.
If `serial=off`, there are no restrictions on transactions.
We can toggle the value of `serial` using the `set_option` ABCI message.
When `serial=on`, some transactions are invalid.
In a live blockchain, transactions collect in memory before they are committed into blocks.
To avoid wasting resources on invalid transactions,
ABCI provides the `check_tx` message,
which application developers can use to accept or reject transactions,
before they are stored in memory or gossipped to other peers.
In this instance of the counter app, `check_tx` only allows transactions whose integer is greater than the last committed one.
Let's kill the console and the dummy application, and start the counter app:
```
counter
```
In another window, start the `abci-cli console`:
```
> set_option serial on
-> data: serial=on
> 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
-> data: {"hashes":0,"txs":2}
```
This is a very simple application, but between `counter` and `dummy`, its easy to see how you can build out arbitrary application states on top of the ABCI.
[Hyperledger's Burrow](https://github.com/hyperledger/burrow) also runs atop ABCI, bringing with it Ethereum-like accounts, the Ethereum virtual-machine, Monax's permissioning scheme, and native contracts extensions.
But the ultimate flexibility comes from being able to write the application easily in any language.
We have implemented the counter in a number of languages (see the example directory).
To run the Node JS version, `cd` to `example/js` and run
```
node app.js
```
(you'll have to kill the other counter application process).
In another window, run the console and those previous ABCI commands.
You should get the same results as for the Go version.
Want to write the counter app in your favorite language?! We'd be happy to add you to our [ecosystem](https://tendermint.com/ecosystem)! We're also offering [bounties](https://tendermint.com/bounties) for implementations in new languages!
## Notes
The `abci-cli` is designed strictly for testing and debugging.
In a real deployment, the role of sending messages is taken by Tendermint,
which connects to the app using three separate connections,
each with its own pattern of messages.
For more information, see the [application developers guide](/docs/guides/app-development).
For examples of running an ABCI app with Tendermint, see the [introductory guide](/docs/getting-started/first-abci-app).

+ 0
- 64
docs/guides/app-architecture.md View File

@ -1,64 +0,0 @@
# Application Architecture Guide
## Overview
A blockchain application is more than the consensus engine and the transaction logic (eg. smart contracts, business logic) as implemented in the ABCI app. There are also (mobile, web, desktop) clients that will need to connect and make use of the app. We will assume for now that you have a well designed transactions and database model, but maybe this will be the topic of another article. This article is more interested in various ways of setting up the "plumbing" and connecting these pieces, and demonstrating some evolving best practices.
## Security
A very important aspect when constructing a blockchain is security. The consensus model can be DoSed (no consensus possible) by corrupting 1/3 of the validators and exploited (writing arbitrary blocks) by corrupting 2/3 of the validators. So, while the security is not that of the "weakest link", you should take care that the "average link" is sufficiently hardened.
One big attack surface on the validators is the communication between the ABCI app and the tendermint core. This should be highly protected. Ideally, the app and the core are running on the same machine, so no external agent can target the communication channel. You can use unix sockets (with permissions preventing access from other users), or even compile the two apps into one binary if the ABCI app is also writen in go. If you are unable to do that due to language support, then the ABCI app should bind a TCP connection to localhost (127.0.0.1), which is less efficient and secure, but still not reachable from outside. If you must run the ABCI app and tendermint core on separate machines, make sure you have a secure communication channel (ssh tunnel?)
Now assuming, you have linked together your app and the core securely, you must also make sure no one can get on the machine it is hosted on. At this point it is basic network security. Run on a secure operating system (SELinux?). Limit who has access to the machine (user accounts, but also where the physical machine is hosted). Turn off all services except for ssh, which should only be accessible by some well-guarded public/private key pairs (no password). And maybe even firewall off access to the ports used by the validators, so only known validators can connect.
There was also a suggestion on slack from @jhon about compiling everything together with a unikernel for more security, such as [Mirage](https://mirage.io) or [UNIK](https://github.com/emc-advanced-dev/unik).
## Connecting your client to the blockchain
### Tendermint Core RPC
The concept is that the ABCI app is completely hidden from the outside world and only communicated through a tested and secured [interface exposed by the tendermint core](/docs/specs/rpc). This interface exposes a lot of data on the block header and consensus process, which is quite useful for externally verifying the system. It also includes 3(!) methods to broadcast a transaction (propose it for the blockchain, and possibly await a response). And one method to query app-specific data from the ABCI application.
Pros:
* Server code already written
* Access to block headers to validate merkle proofs (nice for light clients)
* Basic read/write functionality is supported
Cons:
* Limited interface to app. All queries must be serialized into []byte (less expressive than JSON over HTTP) and there is no way to push data from ABCI app to the client (eg. notify me if account X receives a transaction)
### Custom ABCI server
This was proposed by @wolfposd on slack and demonstrated by [TMChat](https://github.com/wolfposd/TMChat), a sample app. The concept is to write a custom server for your app (with typical REST API/websockets/etc for easy use by a mobile app). This custom server is in the same binary as the ABCI app and data store, so can easily react to complex events there that involve understanding the data format (send a message if my balance drops below 500). All "writes" sent to this server are proxied via websocket/JSON-RPC to tendermint core. When they come back as deliver_tx over ABCI, they will be written to the data store. For "reads", we can do any queries we wish that are supported by our architecture, using any web technology that is useful. The general architecture is shown in the following diagram:
<img alt="Application Architecture" src="../assets/images/tm-app-example.png">
Pros:
* Separates application logic from blockchain logic
* Allows much richer, more flexible client-facing API
* Allows pub-sub, watching certain fields, etc.
Cons:
* Access to ABCI app can be dangerous (be VERY careful not to write unless it comes from the validator node)
* No direct access to the blockchain headers to verify tx
* You must write your own API (but maybe that's a pro...)
### Hybrid solutions
Likely the least secure but most versatile. The client can access both the tendermint node for all blockchain info, as well as a custom app server, for complex queries and pub-sub on the abci app.
Pros:
* All from both above solutions
Cons:
* Even more complexity
* Even more attack vectors (less security)
## Scalability
Read replica using non-validating nodes? They could forward transactions to the validators (fewer connections, more security), and locally allow all queries in any of the above configurations. Thus, while transaction-processing speed is limited by the speed of the abci app and the number of validators, one should be able to scale our read performance to quite an extent (until the replication process drains too many resources from the validator nodes).
## Example Code
* [TMChat](https://github.com/wolfposd/TMChat)

+ 0
- 155
docs/guides/app-development.md View File

@ -1,155 +0,0 @@
# Application Development Guide
## ABCI Design
The purpose of ABCI is to provide a clean interface between state transition machines on one computer and the mechanics of their replication across multiple computers. The former we call 'application logic' and the latter the 'consensus engine'. Application logic validates transactions and optionally executes transactions against some persistent state. A consensus engine ensures all transactions are replicated in the same order on every machine. We call each machine in a consensus engine a 'validator', and each validator runs the same transactions through the same application logic. In particular, we are interested in blockchain-style consensus engines, where transactions are committed in hash-linked blocks.
The ABCI design has a few distinct components:
- message protocol
- pairs of request and response messages
- consensus makes requests, application responds
- defined using protobuf
- server/client
- consensus engine runs the client
- application runs the server
- two implementations:
- async raw bytes
- grpc
- blockchain protocol
- abci is connection oriented
- Tendermint Core maintains three connections:
- [mempool connection](#mempool-connection): for checking if transactions should be relayed before they are committed; only uses `CheckTx`
- [consensus connection](#consensus-connection): for executing transactions that have been committed. Message sequence is - for every block - `BeginBlock, [DeliverTx, ...], EndBlock, Commit`
- [query connection](#query-connection): for querying the application state; only uses Query and Info
<img src="../assets/images/abci.png">
The mempool and consensus logic act as clients, and each maintains an open ABCI connection with the application, which hosts an ABCI server. Shown are the request and response types sent on each connection.
## Message Protocol
The message protocol consists of pairs of requests and responses. Some messages have no fields, while others may include byte-arrays, strings, or integers. See the `message Request` and `message Response` definitions in [the protobuf definition file](https://github.com/tendermint/abci/blob/master/types/types.proto), and the [protobuf documentation](https://developers.google.com/protocol-buffers/docs/overview) for more details.
For each request, a server should respond with the corresponding response, where order of requests is preserved in the order of responses.
## Server
To use ABCI in your programming language of choice, there must be a ABCI server in that language.
Tendermint supports two kinds of implementation of the server:
- Asynchronous, raw socket server (Tendermint Socket Protocol, also known as TSP or Teaspoon)
- GRPC
Both can be tested using the `abci-cli` by setting the `--abci` flag appropriately (ie. to `socket` or `grpc`).
See examples, in various stages of maintenance, in [Go](https://github.com/tendermint/abci/tree/master/server), [JavaScript](https://github.com/tendermint/js-abci), [Python](https://github.com/tendermint/abci/tree/master/example/python3/abci), [C++](https://github.com/mdyring/cpp-tmsp), and [Java](https://github.com/jTendermint/jabci).
### GRPC
If GRPC is available in your language, this is the easiest approach,
though it will have significant performance overhead.
To get started with GRPC, copy in the [protobuf file](https://github.com/tendermint/abci/blob/master/types/types.proto) and compile it using the GRPC plugin for your language.
For instance, for golang, the command is `protoc --go_out=plugins=grpc:. types.proto`. See the [grpc documentation for more details](http://www.grpc.io/docs/). `protoc` will autogenerate all the necessary code for ABCI client and server in your language, including whatever interface your application must satisfy to be used by the ABCI server for handling requests.
### TSP
If GRPC is not available in your language, or you require higher performance, or otherwise enjoy programming, you may implement your own ABCI server
using the Tendermint Socket Protocol, known affectionaltely as Teaspoon.
The first step is still to auto-generate the relevant data types and codec in your language using `protoc`.
Messages coming over the socket are Protobuf3 encoded, but additionally length-prefixed to facilitate use as a streaming protocol. Protobuf3 doesn't have an official length-prefix standard, so we use our own. The first byte in the prefix represents the length of the Big Endian encoded length. The remaining bytes in the prefix are 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....
Note this prefixing does not apply for grpc.
An ABCI server must also be able to support multiple connections, as Tendermint uses three connections.
## Client
There are currently two use-cases for an ABCI client.
One is a testing tool, as in the `abci-cli`, which allows ABCI requests to be sent via command line.
The other is a consensus engine, such as Tendermint Core, which makes requests to the application every time a new transaction is received or a block is committed.
It is unlikely that you will need to implement a client. For details of our client, see [here](https://github.com/tendermint/abci/tree/master/client).
## Blockchain Protocol
In ABCI, a transaction is simply an arbitrary length byte-array.
It is the application's responsibility to define the transaction codec as they please,
and to use it for both CheckTx and DeliverTx.
Note that there are two distinct means for running transactions, corresponding to stages of 'awareness'
of the transaction in the network. The first stage is when a transaction is received by a validator from a client into the so-called mempool or transaction pool - this is where we use CheckTx. The second is when the transaction is successfully committed on more than 2/3 of validators - where we use DeliverTx. In the former case, it may not be necessary to run all the state transitions associated with the transaction, as the transaction may not ultimately be committed until some much later time, when the result of its execution will be different.
For instance, an Ethereum ABCI app would check signatures and amounts in CheckTx, but would not actually execute any contract code until the DeliverTx, so as to avoid executing state transitions that have not been finalized.
To formalize the distinction further, two explicit ABCI connections are made between Tendermint Core and the application: the mempool connection and the consensus connection. We also make a third connection, the query connection, to query the local state of the app.
### Mempool Connection
The mempool connection is used *only* for CheckTx requests.
Transactions are run using CheckTx in the same order they were received by the validator.
If the CheckTx returns `OK`, the transaction is kept in memory and relayed to other peers in the same order it was received. Otherwise, it is discarded.
CheckTx requests run concurrently with block processing;
so they should run against a copy of the main application state which is reset after every block.
This copy is necessary to track transitions made by a sequence of CheckTx requests before they are included in a block. When a block is committed, the application must ensure to reset the mempool state to the latest committed state. Tendermint Core will then filter through all transactions in the mempool, removing any that were included in the block, and re-run the rest using CheckTx against the post-Commit mempool state.
### Consensus Connection
The consensus connection is used only when a new block is committed, and communicates all information from the block in a series of requests: `BeginBlock, [DeliverTx, ...], EndBlock, Commit`.
That is, when a block is committed in the consensus, we send a list of DeliverTx requests (one for each transaction) sandwiched by BeginBlock and EndBlock requests, and followed by a Commit.
#### DeliverTx
DeliverTx is the workhorse of the blockchain. Tendermint sends the DeliverTx requests asynchronously but in order,
and relies on the underlying socket protocol (ie. TCP) to ensure they are received by the app in order. They have already been ordered in the global consensus by the Tendermint protocol.
DeliverTx returns a abci.Result, which includes a Code, Data, and Log. The code may be non-zero (non-OK), meaning the corresponding transaction should have been rejected by the mempool,
but may have been included in a block by a Byzantine proposer.
The block header will be updated (TODO) to include some commitment to the results of DeliverTx, be it a bitarray of non-OK transactions, or a merkle root of the data returned by the DeliverTx requests, or both.
#### Commit
Once all processing of the block is complete, Tendermint sends the Commit request and blocks waiting
for a response. While the mempool may run concurrently with block processing (the BeginBlock, DeliverTxs, and EndBlock), it is locked for the Commit request so that its state can be safely reset during Commit. This means the app *MUST NOT* do any blocking communication with the mempool (ie. broadcast_tx) during Commit, or there will be deadlock. Note also that all remaining transactions in the mempool are replayed on the mempool connection (CheckTx) following a commit.
The Commit response includes a byte array, which is the deterministic state root of the application. It is included in the header of the next block. It can be used to provide easily verified Merkle-proofs of the state of the application.
It is expected that the app will persist state to disk on Commit. The option to have all transactions replayed from some previous block is the job of the [Handshake](#handshake).
#### BeginBlock
The BeginBlock request can be used to run some code at the beginning of every block. It also allows Tendermint to send the current block hash and header to the application, before it sends any of the transactions.
The app should remember the latest height and header (ie. from which it has run a successful Commit) so that it can tell Tendermint where to pick up from when it restarts. See information on the Handshake, below.
#### EndBlock
The EndBlock request can be used to run some code at the end of every block. Additionally, the response may contain a list of validators, which can be used to update the validator set. To add a new validator or update an existing one, simply include them in the list returned in the EndBlock response. To remove one, include it in the list with a `power` equal to `0`. Tendermint core will take care of updating the validator set. Note validator set changes are only available in v0.8.0 and up.
### Query Connection
This connection is used to query the application without engaging consensus. It's exposed over the tendermint core rpc, so clients can query the app without exposing a server on the app itself, but they must serialize each query as a single byte array. Additionally, certain "standardized" queries may be used to inform local decisions, for instance about which peers to connect to.
Tendermint Core currently uses the Query connection to filter peers upon connecting, according to IP address or public key. For instance, returning non-OK ABCI response to either of the following queries will cause Tendermint to not connect to the corresponding peer:
- `p2p/filter/addr/<addr>`, where `<addr>` is an IP address.
- `p2p/filter/pubkey/<pubkey>`, where `<pubkey>` is the hex-encoded ED25519 key of the node (not it's validator key)
Note: these query formats are subject to change!
### Handshake
When the app or tendermint restarts, they need to sync to a common height.
When an ABCI connection is first established, Tendermint will call `Info` on the Query connection.
The response should contain the LastBlockHeight and LastBlockAppHash
- the former is the last block for the which the app ran Commit successfully,
the latter is the response from that Commit.
Using this information, Tendermint will determine what needs to be replayed, if anything, against the app,
to ensure both Tendermint and the app are synced to the latest block height.
If the app returns a LastBlockHeight of 0, Tendermint will just replay all blocks.

+ 0
- 100
docs/guides/install-from-source.md View File

@ -1,100 +0,0 @@
# Install from Source
This page provides instructions on installing Tendermint from source.
To download pre-built binaries, see the [Download page](/download).
## Install Go
Make sure you have [installed Go](https://golang.org/doc/install) and set the `GOPATH`.
## Install Tendermint
You should be able to install the latest with a simple
```
go get github.com/tendermint/tendermint/cmd/tendermint
```
Run `tendermint --help` for more.
If the installation failed, a dependency may been updated and become incompatible with the latest Tendermint master branch.
We solve this using the `glide` tool for dependency management.
Fist, install `glide`:
```
go get github.com/Masterminds/glide
```
Now we can fetch the correct versions of each dependency by running:
```
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
```
Note that even though `go get` originally failed,
the repository was still cloned to the correct location in the `$GOPATH`.
The latest Tendermint Core version is now installed.
### Reinstall
If you already have Tendermint installed, and you make updates,
simply
```
cd $GOPATH/src/github.com/tendermint/tendermint
go install ./cmd/tendermint
```
To upgrade, there are a few options:
- set a new `$GOPATH` and run `go get github.com/tendermint/tendermint/cmd/tendermint`. This makes a fresh copy of everything for the new version.
- run `go get -u github.com/tendermint/tendermint/cmd/tendermint`, where the `-u` fetches the latest updates for the repository and its dependencies
- fetch and checkout the latest master branch in `$GOPATH/src/github.com/tendermint/tendermint`, and then run `glide install && go install ./cmd/tendermint` as above.
Note the first two options should usually work, but may fail.
If they do, use `glide`, as above:
```
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
```
Since the third option just uses `glide` right away, it should always work.
### Troubleshooting
If `go get` failing bothers you, fetch the code using `git`:
```
mkdir -p $GOPATH/src/github.com/tendermint
git clone https://github.com/tendermint/tendermint $GOPATH/src/github.com/tendermint/tendermint
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
```
### Run
To start a one-node blockchain with a simple in-process application:
```
tendermint init
tendermint node --proxy_app=dummy
```
See the
[App Development](/docs/guides/app-development)
guide for more details on building applications,
and the
[Using Tendermint](/docs/guides/using-tendermint)
guide for more details about using the `tendermint` program.
## Next Step
Learn how to [create your first ABCI app](/docs/getting-started/first-abci-app).

+ 0
- 306
docs/guides/using-tendermint.md View File

@ -1,306 +0,0 @@
# Using Tendermint
This is a guide to using the `tendermint` program from the command line.
It assumes only that you [have tendermint installed](/download) and have some rudimentary idea
of what Tendermint and ABCI are.
You can see the help menu with `tendermint --help`, and the version number with `tendermint version`.
## Directory Root
The default directory for blockchain data is `~/.tendermint`. Override this by setting the `TMROOT` environment variable.
## Initialize
Initialize the root directory by running:
```
tendermint init
```
This will create a new private key (`priv_validator.json`), and a genesis file (`genesis.json`) containing the associated public key.
This is all that's necessary to run a local testnet with one validator.
For more elaborate initialization, see our [testnet deployment tool](https://github.com/tendermint/tools/tree/master/mintnet-kubernetes).
## Run
To run a tendermint node, use
```
tendermint node
```
By default, Tendermint will try to connect to a abci appliction on [127.0.0.1:46658](127.0.0.1:46658).
If you have the `dummy` ABCI app installed, run it in another window.
If you don't, kill tendermint and run an in-process version with
```
tendermint node --proxy_app=dummy
```
After a few seconds you should see blocks start streaming in.
Note that blocks are produced regularly, even if there are no transactions.
This changes [with this pull request](https://github.com/tendermint/tendermint/pull/584).
Tendermint supports in-process versions of the dummy, counter, and nil apps that ship as examples in the [ABCI repository](https://github.com/tendermint/abci).
It's easy to compile your own app in-process with tendermint if it's written in Go.
If your app is not written in Go, simply run it in another process,
and use the `--proxy_app` flag to specify the address of the socket it is listening on, for instance
```
tendermint node --proxy_app=/var/run/abci.sock
```
## Transactions
To send a transaction, use `curl` to make requests to the Tendermint RPC server:
```
curl http://localhost:46657/broadcast_tx_commit?tx=\"abcd\"
```
For handling responses, we recommend you [install the jsonpp tool](http://jmhodges.github.io/jsonpp/) to pretty print the JSON.
We can see the chain's status at the `/status` end-point:
```
curl http://localhost:46657/status | jsonpp
```
and the `latest_app_hash` in particular:
```
curl http://localhost:46657/status | jsonpp | grep app_hash
```
Visit [http://localhost:46657](http://localhost:46657) in your browser to see the list of other endpoints.
Some take no arguments (like `/status`), while others specify the argument name and use `_` as a placeholder.
## Reset
**WARNING: UNSAFE** Only do this in development and only if you can afford to lose all blockchain data!
To reset a blockchain, stop the node, remove the `~/.tendermint/data` directory and run
```
tendermint unsafe_reset_priv_validator
```
This final step is necessary to reset the `priv_validator.json`,
which otherwise prevents you from making conflicting votes in the consensus
(something that could get you in trouble if you do it on a real blockchain).
If you don't reset the `priv_validator.json`, your fresh new blockchain will not make any blocks.
## Configuration
Tendermint uses a `config.toml` for configutation. For details, see [the documentation](/docs/specs/configuration).
Notable options include the socket address of the application (`proxy_app`),
the listenting address of the tendermint peer (`p2p.laddr`),
and the listening address of the rpc server (`rpc.laddr`).
Some fields from the config file can be overwritten with flags.
## Broadcast API
Earlier, we used the `broadcast_tx_commit` endpoint to send a transaction.
When a transaction is sent to a tendermint node,
it will run via `CheckTx` against the application.
If it passes `CheckTx`, it will be included in the mempool,
broadcast to other peers, and eventually included in a block.
Since there are multiple phases to processing a transaction, we offer multiple endpoints to broadcast a transaction:
```
/broadcast_tx_async
/broadcast_tx_sync
/broadcast_tx_commit
```
These correspond to no-processing, processing through the mempool, and processing through a block, respectively.
That is, `broadcast_tx_async`, will return right away without waiting to hear if the transaction is even valid,
while `broadcast_tx_sync` will return with the result of running the transaction through `CheckTx`.
Using `broadcast_tx_commit` will wait until the transaction is committed in a block or until some timeout is reached,
but will return right away if the transaction does not pass `CheckTx`.
The return value for `broadcast_tx_commit` includes two fields, `check_tx` and `deliver_tx`, pertaining to the result of running
the transaction through those ABCI messages.
The benefit of using `broadcast_tx_commit` is that the request returns after the transaction is committed (ie. included in a block), but that can take on the order of a second. For a quick result, use `broadcast_tx_sync`,
but the transaction will not be committed until later, and by that point its effect on the state may change.
## Tendermint Networks
When `tendermint init` is run, both a `genesis.json` and `priv_validator.json` are created in `~/.tendermint`.
The `genesis.json` might look like:
```
{
"app_hash": "",
"chain_id": "test-chain-HZw6TB",
"genesis_time": "0001-01-01T00:00:00.000Z",
"validators": [
{
"amount": 10,
"name": "",
"pub_key": [
1,
"5770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
]
}
]
}
```
And the `priv_validator.json`:
```
{
"address": "4F4D895F882A18E1D1FC608D102601DA8D3570E5",
"last_height": 0,
"last_round": 0,
"last_signature": null,
"last_signbytes": "",
"last_step": 0,
"priv_key": [
1,
"F9FA3CD435BDAE54D0BCA8F1BC289D718C23D855C6DB21E8543F5E4F457E62805770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
],
"pub_key": [
1,
"5770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
]
}
```
The `priv_validator.json` actually contains a private key, and should thus be kept absolutely secret;
for now we work with the plain text.
Note the `last_` fields, which are used to prevent us from signing conflicting messages.
Note also that the `pub_key` (the public key) in the `priv_validator.json` is also present in the `genesis.json`.
The genesis file contains the list of public keys which may participate in the consensus,
and their corresponding voting power.
Greater than 2/3 of the voting power must be active (ie. the corresponding private keys must be producing signatures)
for the consensus to make progress.
In our case, the genesis file contains the public key of our `priv_validator.json`,
so a tendermint node started with the default root directory will be able to make new blocks,
as we've already seen.
If we want to add more nodes to the network, we have two choices:
we can add a new validator node, who will also participate in the consensus
by proposing blocks and voting on them,
or we can add a new non-validator node, who will not participate directly,
but will verify and keep up with the consensus protocol.
### Peers
To connect to peers on start-up, specify them in the `config.toml` or on the command line.
For instance,
```
tendermint node --p2p.seeds "1.2.3.4:46656,5.6.7.8:46656"
```
Alternatively, you can use the `/dial_seeds` endpoint of the RPC to specify peers for a running node to connect to:
```
curl --data-urlencode "seeds=[\"1.2.3.4:46656\",\"5.6.7.8:46656\"]" localhost:46657/dial_seeds
```
Additionally, the peer-exchange protocol can be enabled using the `--pex` flag,
though this feature is [still under development](https://github.com/tendermint/tendermint/issues/598)
If `--pex` is enabled, peers will gossip about known peers and form a more resilient network.
### Adding a Non-Validator
Adding a non-validator is simple. Just copy the original `genesis.json` to `~/.tendermint` on the new machine
and start the node, specifying seeds as necessary.
If no seeds are specified, the node won't make any blocks, because it's not a validator,
and it won't hear about any blocks, because it's not connected to the other peer.
### Adding a Validator
The easiest way to add new validators is to do it in the `genesis.json`, before starting the network.
For instance, we could make a new `priv_validator.json`, and copy it's `pub_key` into the above genesis.
We can generate a new `priv_validator.json` with the command:
```
tendermint gen_validator
```
Now we can update our genesis file. For instance, if the new `priv_validator.json` looks like:
```
{
"address": "AC379688105901436A34A65F185C115B8BB277A1",
"last_height": 0,
"last_round": 0,
"last_signature": null,
"last_signbytes": "",
"last_step": 0,
"priv_key": [
1,
"0D2ED337D748ADF79BE28559B9E59EBE1ABBA0BAFE6D65FCB9797985329B950C8F2B5AACAACC9FCE41881349743B0CFDE190DF0177744568D4E82A18F0B7DF94"
],
"pub_key": [
1,
"8F2B5AACAACC9FCE41881349743B0CFDE190DF0177744568D4E82A18F0B7DF94"
]
}
```
then the new `genesis.json` will be:
```
{
"app_hash": "",
"chain_id": "test-chain-HZw6TB",
"genesis_time": "0001-01-01T00:00:00.000Z",
"validators": [
{
"amount": 10,
"name": "",
"pub_key": [
1,
"5770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
]
},
{
"amount": 10,
"name": "",
"pub_key": [
1,
"8F2B5AACAACC9FCE41881349743B0CFDE190DF0177744568D4E82A18F0B7DF94"
]
}
]
}
```
Update the `genesis.json` in `~/.tendermint`. Copy the genesis file and the new `priv_validator.json`
to the `~/.tendermint` on a new machine.
Now run `tendermint node` on both machines, and use either `--p2p.seeds` or the `/dial_seeds` to get them to peer up.
They should start making blocks, and will only continue to do so as long as both of them are online.
To make a Tendermint network that can tolerate one of the validators failing, you need at least four validator nodes (> 2/3).
Updating validators in a live network is supported but must be explicitly programmed by the application developer.
See the [application developers guide](/docs/guides/app-development#Handshake) for more details.
### Local Network
To run a network locally, say on a single machine, you must change the `_laddr` fields in the `config.toml` (or using the flags)
so that the listening addresses of the various sockets don't conflict.
Additionally, you must set `addrbook_strict=false` in the `config.toml`,
otherwise Tendermint's p2p library will deny making connections to peers with the same IP address.
## More
Got a couple nodes talking to each other using the dummy app?
Try a more sophisticated app like [Ethermint](https://github.com/tendermint/ethermint),
or learn more about building your own in the [Application Developer's Guide](/docs/guides/app-development).

BIN
docs/images/abci.png View File

Before After
Width: 1492  |  Height: 1257  |  Size: 43 KiB

BIN
docs/images/consensus_logic.png View File

Before After
Width: 2006  |  Height: 1404  |  Size: 103 KiB

BIN
docs/images/tm-transaction-flow.png View File

Before After
Width: 3334  |  Height: 3334  |  Size: 2.4 MiB

BIN
docs/images/tmint-logo-blue.png View File

Before After
Width: 2048  |  Height: 2048  |  Size: 52 KiB

+ 0
- 28
docs/index.md View File

@ -1,28 +0,0 @@
# Documentation
If you're new here, start with the [Tendermint Intro](/intro).
To start building an ABCI application and integrating with Tendermint,
see the [App Development](/docs/guides/app-development)
and [App Architecture](/docs/guides/app-architecture) guides.
To learn more about running the Tendermint software, see the [Using Tendermint Guide](/docs/guides/using-tendermint).
To learn more about Tendermint's various pieces, check out the [Documentation](/docs).
For a deeper dive, see [this thesis](https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769).
There is also the [original whitepaper](https://tendermint.com/static/docs/tendermint.pdf), though it is now quite outdated.
You might also be interested in the [Cosmos Whitepaper](https://cosmos.network/whitepaper),
which describes Tendermint, ABCI, and how to build a scalable, heterogeneous, cryptocurrency network.
For details on how the software has changed, and what changes are in store, see the [Changelog](https://github.com/tendermint/tendermint/blob/master/CHANGELOG.md) and the [Roadmap](https://github.com/tendermint/tendermint/blob/master/roadmap.md).
If you're interested in contributing, see our [Contributor Guidelines](https://github.com/tendermint/tendermint/blob/master/CONTRIBUTING.md)
The Tendermint [Software Ecosystem](/ecosystem) contains many example applications and related software built by the Tendermint team and others.
Check it out for some motivation and inspiration!
See our [Community](/community) page for more ways to collaborate.
You can also [get in touch with the team](/contact).
Most importantly, enjoy!

+ 52
- 0
docs/index.rst View File

@ -0,0 +1,52 @@
.. Tendermint documentation master file, created by
sphinx-quickstart on Mon Aug 7 04:55:09 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Tendermint!
======================
.. image:: assets/tmint-logo-blue.png
:height: 500px
:width: 500px
:align: center
Tendermint 101
--------------
.. maxdepth set to 2 for sexinesss
.. but use 4 to upgrade overall documentation
.. toctree::
:maxdepth: 2
introduction.rst
install.rst
getting-started.rst
deploy-testnets.rst
using-tendermint.rst
Tendermint 102
--------------
.. toctree::
:maxdepth: 2
abci-cli.rst
app-architecture.rst
app-development.rst
Tendermint 201
--------------
.. toctree::
:maxdepth: 2
specification.rst
* For a deeper dive, see `this thesis <https://atrium.lib.uoguelph.ca/xmlui/handle/10214/9769>`__.
* There is also the `original whitepaper <https://tendermint.com/static/docs/tendermint.pdf>`__, though it is now quite outdated.
* Readers might also be interested in the `Cosmos Whitepaper <https://cosmos.network/whitepaper>`__ which describes Tendermint, ABCI, and how to build a scalable, heterogeneous, cryptocurrency network.
* For example applications and related software built by the Tendermint team and other, see the `software ecosystem <https://tendermint.com/ecosystem>`__.
Join the `Cosmos and Tendermint Rocket Chat <https://cosmos.rocket.chat>`__ to ask questions and discuss projects.

+ 102
- 0
docs/install.rst View File

@ -0,0 +1,102 @@
Install from Source
===================
This page provides instructions on installing Tendermint from source. To
download pre-built binaries, see the `Download page <https://tendermint.com/download>`__.
Install Go
----------
Make sure you have `installed Go <https://golang.org/doc/install>`__ and
set the ``GOPATH``.
Install Tendermint
------------------
You should be able to install the latest with a simple
::
go get github.com/tendermint/tendermint/cmd/tendermint
Run ``tendermint --help`` for more.
If the installation failed, a dependency may been updated and become
incompatible with the latest Tendermint master branch. We solve this
using the ``glide`` tool for dependency management.
Fist, install ``glide``:
::
go get github.com/Masterminds/glide
Now we can fetch the correct versions of each dependency by running:
::
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
Note that even though ``go get`` originally failed, the repository was
still cloned to the correct location in the ``$GOPATH``.
The latest Tendermint Core version is now installed.
Reinstall
~~~~~~~~~
If you already have Tendermint installed, and you make updates, simply
::
cd $GOPATH/src/github.com/tendermint/tendermint
go install ./cmd/tendermint
To upgrade, there are a few options:
- set a new ``$GOPATH`` and run
``go get github.com/tendermint/tendermint/cmd/tendermint``. This
makes a fresh copy of everything for the new version.
- run ``go get -u github.com/tendermint/tendermint/cmd/tendermint``,
where the ``-u`` fetches the latest updates for the repository and
its dependencies
- fetch and checkout the latest master branch in
``$GOPATH/src/github.com/tendermint/tendermint``, and then run
``glide install && go install ./cmd/tendermint`` as above.
Note the first two options should usually work, but may fail. If they
do, use ``glide``, as above:
::
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
Since the third option just uses ``glide`` right away, it should always
work.
Troubleshooting
~~~~~~~~~~~~~~~
If ``go get`` failing bothers you, fetch the code using ``git``:
::
mkdir -p $GOPATH/src/github.com/tendermint
git clone https://github.com/tendermint/tendermint $GOPATH/src/github.com/tendermint/tendermint
cd $GOPATH/src/github.com/tendermint/tendermint
glide install
go install ./cmd/tendermint
Run
~~~
To start a one-node blockchain with a simple in-process application:
::
tendermint init
tendermint node --proxy_app=dummy

+ 231
- 0
docs/introduction.rst View File

@ -0,0 +1,231 @@
Introduction
============
Welcome to the Tendermint guide! This is the best place to start if you are new
to Tendermint.
What is Tendermint?
-------------------
Tendermint is software for securely and consistently replicating an application on many machines.
By securely, we mean that Tendermint works even if up to 1/3 of machines fail in arbitrary ways.
By consistently, we mean that every non-faulty machine sees the same transaction log and computes the same state.
Secure and consistent replication is a fundamental problem in distributed systems;
it plays a critical role in the fault tolerance of a broad range of applications,
from currencies, to elections, to infrastructure orchestration, and beyond.
The ability to tolerate machines failing in arbitrary ways, including becoming malicious, is known as Byzantine fault tolerance (BFT).
The theory of BFT is decades old, but software implementations have only became popular recently,
due largely to the success of "blockchain technology" like Bitcoin and Ethereum.
Blockchain technology is just a reformalization of BFT in a more modern setting,
with emphasis on peer-to-peer networking and cryptographic authentication.
The name derives from the way transactions are batched in blocks,
where each block contains a cryptographic hash of the previous one, forming a chain.
In practice, the blockchain data structure actually optimizes BFT design.
Tendermint consists of two chief technical components: a blockchain consensus engine and a generic application interface.
The consensus engine, called Tendermint Core, ensures that the same transactions are recorded on every machine in the same order.
The application interface, called the Application BlockChain Interface (ABCI), enables the transactions to be processed in any programming language.
Unlike other blockchain and consensus solutions, which come pre-packaged with built in state machines (like a fancy key-value store,
or a quirky scripting language), developers can use Tendermint for BFT state machine replication of applications written in
whatever programming language and development environment is right for them.
Tendermint is designed to be easy-to-use, simple-to-understand, highly performant, and useful
for a wide variety of distributed applications.
Tendermint vs. X
----------------
Tendermint vs. Other Software
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tendermint is broadly similar to two classes of software.
The first class consists of distributed key-value stores,
like Zookeeper, etcd, and consul, which use non-BFT consensus.
The second class is known as "blockchain technology",
and consists of both cryptocurrencies like Bitcoin and Ethereum,
and alternative distributed ledger designs like Hyperledger's Burrow.
Zookeeper, etcd, consul
~~~~~~~~~~~~~~~~~~~~~~~
Zookeeper, etcd, and consul are all implementations of a key-value store atop a classical,
non-BFT consensus algorithm. Zookeeper uses a version of Paxos called Zookeeper Atomic Broadcast,
while etcd and consul use the Raft consensus algorithm, which is much younger and simpler.
A typical cluster contains 3-5 machines, and can tolerate crash failures in up to 1/2 of the machines,
but even a single Byzantine fault can destroy the system.
Each offering provides a slightly different implementation of a featureful key-value store,
but all are generally focused around providing basic services to distributed systems,
such as dynamic configuration, service discovery, locking, leader-election, and so on.
Tendermint is in essence similar software, but with two key differences:
- It is Byzantine Fault Tolerant, meaning it can only tolerate up to a 1/3 of failures,
but those failures can include arbitrary behaviour - including hacking and malicious attacks.
- It does not specify a particular application, like a fancy key-value store. Instead,
it focuses on arbitrary state machine replication, so developers can build the application logic
that's right for them, from key-value store to cryptocurrency to e-voting platform and beyond.
The layout of this Tendermint website content is also ripped directly and without shame from
`consul.io <https://www.consul.io/>`__ and the other `Hashicorp sites <https://www.hashicorp.com/#tools>`__.
Bitcoin, Ethereum, etc.
~~~~~~~~~~~~~~~~~~~~~~~
Tendermint emerged in the tradition of cryptocurrencies like Bitcoin, Ethereum, etc.
with the goal of providing a more efficient and secure consensus algorithm than Bitcoin's Proof of Work.
In the early days, Tendermint had a simple currency built in, and to participate in consensus,
users had to "bond" units of the currency into a security deposit which could be revoked if they misbehaved -
this is what made Tendermint a Proof-of-Stake algorithm.
Since then, Tendermint has evolved to be a general purpose blockchain consensus engine that can host arbitrary application states.
That means it can be used as a plug-and-play replacement for the consensus engines of other blockchain software.
So one can take the current Ethereum code base, whether in Rust, or Go, or Haskell, and run it as a ABCI application
using Tendermint consensus. Indeed, `we did that with Ethereum <https://github.com/tendermint/ethermint>`__.
And we plan to do the same for Bitcoin, ZCash, and various other deterministic applications as well.
Another example of a cryptocurrency application built on Tendermint is `the Cosmos network <http://cosmos.network>`__.
Fabric, Burrow
~~~~~~~~~~~~~~
`Fabric <https://github.com/hyperledger/fabric>`__, takes a similar approach to Tendermint, but is more opinionated about how the state is managed,
and requires that all application behaviour runs in potentially many docker containers, modules it calls "chaincode".
It uses an implementation of `PBFT <http://pmg.csail.mit.edu/papers/osdi99.pdf>`__.
from a team at IBM that is
`augmented to handle potentially non-deterministic chaincode <https://www.zurich.ibm.com/~cca/papers/sieve.pdf>`__
It is possible to implement this docker-based behaviour as a ABCI app in Tendermint,
though extending Tendermint to handle non-determinism remains for future work.
`Burrow <https://github.com/hyperledger/burrow>`__ is an implementation of the Ethereum Virtual Machine and Ethereum transaction mechanics,
with additional features for a name-registry, permissions, and native contracts, and an alternative blockchain API.
It uses Tendermint as its consensus engine, and provides a particular application state.
ABCI Overview
-------------
The `Application BlockChain Interface (ABCI) <https://github.com/tendermint/abci>`__ allows for Byzantine Fault Tolerant replication of applications written in any programming language.
Motivation
~~~~~~~~~~
Thus far, all blockchains "stacks" (such as `Bitcoin <https://github.com/bitcoin/bitcoin>`__) have had a monolithic design. That is, each blockchain stack is a single program that handles all the concerns of a decentralized ledger; this includes P2P connectivity, the "mempool" broadcasting of transactions, consensus on the most recent block, account balances, Turing-complete contracts, user-level permissions, etc.
Using a monolithic architecture is typically bad practice in computer science.
It makes it difficult to reuse components of the code, and attempts to do so result in complex maintanence procedures for forks of the codebase.
This is especially true when the codebase is not modular in design and suffers from "spaghetti code".
Another problem with monolithic design is that it limits you to the language of the blockchain stack (or vice versa). In the case of Ethereum which supports a Turing-complete bytecode virtual-machine, it limits you to languages that compile down to that bytecode; today, those are Serpent and Solidity.
In contrast, our approach is to decouple the consensus engine and P2P layers from the details of the application state of the particular blockchain application.
We do this by abstracting away the details of the application to an interface, which is implemented as a socket protocol.
Thus we have an interface, the Application BlockChain Interface (ABCI), and its primary implementation, the Tendermint Socket Protocol (TSP, or Teaspoon).
Intro to ABCI
~~~~~~~~~~~~~
`Tendermint Core <https://github.com/tendermint/tendermint>`__ (the "consensus engine") communicates with the application via a socket protocol that
satisfies the `ABCI <https://github.com/tendermint/abci>`__.
To draw an analogy, lets talk about a well-known cryptocurrency, Bitcoin. Bitcoin is a cryptocurrency blockchain where each node maintains a fully audited Unspent Transaction Output (UTXO) database. If one wanted to create a Bitcoin-like system on top of ABCI, Tendermint Core would be responsible for
- Sharing blocks and transactions between nodes
- Establishing a canonical/immutable order of transactions (the blockchain)
The application will be responsible for
- Maintaining the UTXO database
- Validating cryptographic signatures of transactions
- Preventing transactions from spending non-existent transactions
- Allowing clients to query the UTXO database.
Tendermint is able to decompose the blockchain design by offering a very simple API (ie. the ABCI) between the application process and consensus process.
The ABCI consists of 3 primary message types that get delivered from the core to the application. The application replies with corresponding response messages.
The messages are specified here: `ABCI Message Types <https://github.com/tendermint/abci#message-types>`__.
The `DeliverTx` message is the work horse of the application. Each transaction in the blockchain is delivered with this message. The application needs to validate each transaction received with the `DeliverTx` message against the current state, application protocol, and the cryptographic credentials of the transaction. A validated transaction then needs to update the application state — by binding a value into a key values store, or by updating the UTXO database, for instance.
The `CheckTx` message is similar to `DeliverTx`, but it's only for validating transactions. Tendermint Core's mempool first checks the validity of a transaction with `CheckTx`, and only relays valid transactions to its peers. For instance, an application may check an incrementing sequence number in the transaction and return an error upon `CheckTx` if the sequence number is old. Alternatively, they might use a capabilities based system that requires capabilities to be renewed with every transaction.
The `Commit` message is used to compute a cryptographic commitment to the current application state, to be placed into the next block header. This has some handy properties. Inconsistencies in updating that state will now appear as blockchain forks which catches a whole class of programming errors. This also simplifies the development of secure lightweight clients, as Merkle-hash proofs can be verified by checking against the block hash, and that the block hash is signed by a quorum.
There can be multiple ABCI socket connections to an application. Tendermint Core creates three ABCI connections to the application; one for the validation of transactions when broadcasting in the mempool, one for the consensus engine to run block proposals, and one more for querying the application state.
It's probably evident that applications designers need to very carefully design their message handlers to create a blockchain that does anything useful but this architecture provides a place to start. The diagram below illustrates the flow of messages via ABCI.
.. figure:: images/abci.png
A Note on Determinism
~~~~~~~~~~~~~~~~~~~~~
The logic for blockchain transaction processing must be deterministic. If the application logic weren't deterministic, consensus would not be reached among the Tendermint Core replica nodes.
Solidity on Ethereum is a great language of choice for blockchain applications because, among other reasons, it is a completely deterministic programming language. However, it's also possible to create deterministic applications using existing popular languages like Java, C++, Python, or Go. Game programmers and blockchain developers are already familiar with creating deterministic programs by avoiding sources of non-determinism such as:
* random number generators (without deterministic seeding)
* race conditions on threads (or avoiding threads altogether)
* the system clock
* uninitialized memory (in unsafe programming languages like C or C++)
* `floating point arithmetic <http://gafferongames.com/networking-for-game-programmers/floating-point-determinism/>`__.
* language features that are random (e.g. map iteration in Go)
While programmers can avoid non-determinism by being careful, it is also possible to create a special linter or static analyzer for each language to check for determinism. In the future we may work with partners to create such tools.
Consensus Overview
------------------
Tendermint is an easy-to-understand, mostly asynchronous, BFT consensus protocol.
The protocol follows a simple state machine that looks like this:
.. figure:: images/consensus_logic.png
Participants in the protocol are called "validators";
they take turns proposing blocks of transactions and voting on them.
Blocks are committed in a chain, with one block at each "height".
A block may fail to be committed, in which case the protocol moves to the next "round",
and a new validator gets to propose a block for that height.
Two stages of voting are required to successfully commit a block;
we call them "pre-vote" and "pre-commit".
A block is committed when more than 2/3 of validators pre-commit for the same block in the same round.
There is a picture of a couple doing the polka because validators are doing something like a polka dance.
When more than two-thirds of the validators pre-vote for the same block, we call that a "polka".
Every pre-commit must be justified by a polka in the same round.
Validators may fail to commit a block for a number of reasons;
the current proposer may be offline, or the network may be slow.
Tendermint allows them to establish that a validator should be skipped.
Validators wait a small amount of time to receive a complete proposal block from the proposer before voting to move to the next round.
This reliance on a timeout is what makes Tendermint a weakly synchronous protocol, rather than an asynchronous one.
However, the rest of the protocol is asynchronous, and validators only make progress after hearing from more than two-thirds of the validator set.
A simplifying element of Tendermint is that it uses the same mechanism to commit a block as it does to skip to the next round.
Assuming less than one-third of the validators are Byzantine, Tendermint guarantees that safety will never be violated - that is, validators will never commit conflicting blocks at the same height.
To do this it introduces a few "locking" rules which modulate which paths can be followed in the flow diagram.
Once a validator precommits a block, it is "locked" on that block.
Then,
1) it must prevote for the block it is locked on
2) it can only unlock, and precommit for a new block, if there is a polka for that block in a later round
Stake
-----
In many systems, not all validators will have the same "weight" in the consensus protocol.
Thus, we are not so much interested in one-third or two-thirds of the validators, but in those proportions of the total voting power,
which may not be uniformly distributed across individual validators.
Since Tendermint can replicate arbitrary applications, it is possible to define a currency, and denominate the voting power in that currency.
When voting power is denominated in a native currency, the system is often referred to as Proof-of-Stake.
Validators can be forced, by logic in the application,
to "bond" their currency holdings in a security deposit that can be destroyed if they're found to misbehave in the consensus protocol.
This adds an economic element to the security of the protocol, allowing one to quantify the cost of violating the assumption that less than one-third of voting power is Byzantine.
The `Cosmos Network <http://cosmos.network>`__ is designed to use this Proof-of-Stake mechanism across an array of cryptocurrencies implemented as ABCI applications.
The following diagram is Tendermint in a (technical) nutshell. `See here for high resolution version <https://github.com/mobfoundry/hackatom/blob/master/tminfo.pdf>`__.
.. figure:: images/tm-transaction-flow.png

+ 33
- 0
docs/light-client-protocol.rst View File

@ -0,0 +1,33 @@
Light Client Protocol
=====================
Light clients are an important part of the complete blockchain system
for most applications. Tendermint provides unique speed and security
properties for light client applications.
See our developing `light-client
repository <https://github.com/tendermint/light-client>`__.
Overview
--------
The objective of the light client protocol is to get a
`commit <./validators.html#committing-a-block>`__ for a recent
`block hash <./block-structure.html#block-hash>`__ where the commit
includes a majority of signatures from the last known validator set.
From there, all the application state is verifiable with `merkle
proofs <./merkle-trees#iavl-tree>`__.
Properties
----------
- You get the full collateralized security benefits of Tendermint; No
need to wait for confirmations.
- You get the full speed benefits of Tendermint; transactions commit
instantly.
- You can get the most recent version of the application state
non-interactively (without committing anything to the blockchain).
For example, this means that you can get the most recent value of a
name from the name-registry without worrying about fork censorship
attacks, without posting a commit and waiting for confirmations. It's
fast, secure, and free!

+ 88
- 0
docs/merkle.rst View File

@ -0,0 +1,88 @@
Merkle
======
For an overview of Merkle trees, see
`wikipedia <https://en.wikipedia.org/wiki/Merkle_tree>`__.
There are two types of Merkle trees used in Tendermint.
- ```IAVL+ Tree`` <#iavl-tree>`__: An immutable self-balancing binary
tree for persistent application state
- ```Simple Tree`` <#simple-tree>`__: A simple compact binary tree for
a static list of items
IAVL+ Tree
----------
The purpose of this data structure is to provide persistent storage for
key-value pairs (e.g. account state, name-registrar data, and
per-contract data) such that a deterministic merkle root hash can be
computed. The tree is balanced using a variant of the `AVL
algorithm <http://en.wikipedia.org/wiki/AVL_tree>`__ so all operations
are O(log(n)).
Nodes of this tree are immutable and indexed by its hash. Thus any node
serves as an immutable snapshot which lets us stage uncommitted
transactions from the mempool cheaply, and we can instantly roll back to
the last committed state to process transactions of a newly committed
block (which may not be the same set of transactions as those from the
mempool).
In an AVL tree, the heights of the two child subtrees of any node differ
by at most one. Whenever this condition is violated upon an update, the
tree is rebalanced by creating O(log(n)) new nodes that point to
unmodified nodes of the old tree. In the original AVL algorithm, inner
nodes can also hold key-value pairs. The AVL+ algorithm (note the plus)
modifies the AVL algorithm to keep all values on leaf nodes, while only
using branch-nodes to store keys. This simplifies the algorithm while
minimizing the size of merkle proofs
In Ethereum, the analog is the `Patricia
trie <http://en.wikipedia.org/wiki/Radix_tree>`__. There are tradeoffs.
Keys do not need to be hashed prior to insertion in IAVL+ trees, so this
provides faster iteration in the key space which may benefit some
applications. The logic is simpler to implement, requiring only two
types of nodes -- inner nodes and leaf nodes. The IAVL+ tree is a binary
tree, so merkle proofs are much shorter than the base 16 Patricia trie.
On the other hand, while IAVL+ trees provide a deterministic merkle root
hash, it depends on the order of updates. In practice this shouldn't be
a problem, since you can efficiently encode the tree structure when
serializing the tree contents.
Simple Tree
-----------
For merkelizing smaller static lists, use the Simple Tree. The
transactions and validation signatures of a block are hashed using this
simple merkle tree logic.
If the number of items is not a power of two, the tree will not be full
and some leaf nodes will be at different levels. Simple Tree tries to
keep both sides of the tree the same size, but the left side may be one
greater.
::
Simple Tree with 6 items Simple Tree with 7 items
* *
/ \ / \
/ \ / \
/ \ / \
/ \ / \
* * * *
/ \ / \ / \ / \
/ \ / \ / \ / \
/ \ / \ / \ / \
* h2 * h5 * * * h6
/ \ / \ / \ / \ / \
h0 h1 h3 h4 h0 h1 h2 h3 h4 h5
Simple Tree with Dictionaries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Simple Tree is used to merkelize a list of items, so to merkelize a
(short) dictionary of key-value pairs, encode the dictionary as an
ordered list of ``KVPair`` structs. The block hash is such a hash
derived from all the fields of the block ``Header``. The state hash is
similarly derived.

+ 4
- 0
docs/requirements.txt View File

@ -0,0 +1,4 @@
sphinx
sphinx-autobuild
recommonmark
sphinx_rtd_theme

+ 188
- 0
docs/rpc.rst View File

@ -0,0 +1,188 @@
RPC
===
Coming soon: RPC docs powered by `slate <https://github.com/lord/slate>`__. Until then, read on.
Tendermint supports the following RPC protocols:
- URI over HTTP
- JSONRPC over HTTP
- JSONRPC over websockets
Tendermint RPC is build using `our own RPC
library <https://github.com/tendermint/tendermint/tree/master/rpc/lib>`__.
Documentation and tests for that library could be found at
``tendermint/rpc/lib`` directory.
Configuration
~~~~~~~~~~~~~
Set the ``laddr`` config parameter under ``[rpc]`` table in the
$TMHOME/config.toml file or the ``--rpc.laddr`` command-line flag to the
desired protocol://host:port setting. Default: ``tcp://0.0.0.0:46657``.
Arguments
~~~~~~~~~
Arguments which expect strings or byte arrays may be passed as quoted
strings, like ``"abc"`` or as ``0x``-prefixed strings, like
``0x616263``.
URI/HTTP
~~~~~~~~
Example request:
.. code:: bash
curl -s 'http://localhost:46657/broadcast_tx_sync?tx="abc"' | jq .
Response:
.. code:: json
{
"error": "",
"result": {
"hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
"log": "",
"data": "",
"code": 0
},
"id": "",
"jsonrpc": "2.0"
}
The first entry in the result-array (``96``) is the method this response
correlates with. ``96`` refers to "ResultTypeBroadcastTx", see
`responses.go <https://github.com/tendermint/tendermint/blob/master/rpc/core/types/responses.go>`__
for a complete overview.
JSONRPC/HTTP
~~~~~~~~~~~~
JSONRPC requests can be POST'd to the root RPC endpoint via HTTP (e.g.
``http://localhost:46657/``).
Example request:
.. code:: json
{
"method": "broadcast_tx_sync",
"jsonrpc": "2.0",
"params": [ "abc" ],
"id": "dontcare"
}
JSONRPC/websockets
~~~~~~~~~~~~~~~~~~
JSONRPC requests can be made via websocket. The websocket endpoint is at
``/websocket``, e.g. ``http://localhost:46657/websocket``. Asynchronous
RPC functions like event ``subscribe`` and ``unsubscribe`` are only
available via websockets.
Endpoints
~~~~~~~~~
An HTTP Get request to the root RPC endpoint (e.g.
``http://localhost:46657``) shows a list of available endpoints.
::
Available endpoints:
http://localhost:46657/abci_info
http://localhost:46657/dump_consensus_state
http://localhost:46657/genesis
http://localhost:46657/net_info
http://localhost:46657/num_unconfirmed_txs
http://localhost:46657/status
http://localhost:46657/unconfirmed_txs
http://localhost:46657/unsafe_flush_mempool
http://localhost:46657/unsafe_stop_cpu_profiler
http://localhost:46657/validators
Endpoints that require arguments:
http://localhost:46657/abci_query?path=_&data=_&prove=_
http://localhost:46657/block?height=_
http://localhost:46657/blockchain?minHeight=_&maxHeight=_
http://localhost:46657/broadcast_tx_async?tx=_
http://localhost:46657/broadcast_tx_commit?tx=_
http://localhost:46657/broadcast_tx_sync?tx=_
http://localhost:46657/commit?height=_
http://localhost:46657/dial_seeds?seeds=_
http://localhost:46657/subscribe?event=_
http://localhost:46657/tx?hash=_&prove=_
http://localhost:46657/unsafe_start_cpu_profiler?filename=_
http://localhost:46657/unsafe_write_heap_profile?filename=_
http://localhost:46657/unsubscribe?event=_
tx
~~
Returns a transaction matching the given transaction hash.
**Parameters**
1. hash - the transaction hash
2. prove - include a proof of the transaction inclusion in the block in
the result (optional, default: false)
**Returns**
- ``proof``: the ``types.TxProof`` object
- ``tx``: ``[]byte`` - the transaction
- ``tx_result``: the ``abci.Result`` object
- ``index``: ``int`` - index of the transaction
- ``height``: ``int`` - height of the block where this transaction was
in
**Example**
.. code:: bash
curl -s 'http://localhost:46657/broadcast_tx_commit?tx="abc"' | jq .
# {
# "error": "",
# "result": {
# "hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
# "log": "",
# "data": "",
# "code": 0
# },
# "id": "",
# "jsonrpc": "2.0"
# }
curl -s 'http://localhost:46657/tx?hash=0x2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF' | jq .
# {
# "error": "",
# "result": {
# "proof": {
# "Proof": {
# "aunts": []
# },
# "Data": "YWJjZA==",
# "RootHash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
# "Total": 1,
# "Index": 0
# },
# "tx": "YWJjZA==",
# "tx_result": {
# "log": "",
# "data": "",
# "code": 0
# },
# "index": 0,
# "height": 52
# },
# "id": "",
# "jsonrpc": "2.0"
# }
More Examples
~~~~~~~~~~~~~
See the various bash tests using curl in ``test/``, and examples using
the ``Go`` API in ``rpc/client/``.

+ 73
- 0
docs/secure-p2p.rst View File

@ -0,0 +1,73 @@
Secure P2P
==========
The Tendermint p2p protocol uses an authenticated encryption scheme
based on the `Station-to-Station
Protocol <https://en.wikipedia.org/wiki/Station-to-Station_protocol>`__.
The implementation uses
`golang's <https://godoc.org/golang.org/x/crypto/nacl/box>`__ `nacl
box <http://nacl.cr.yp.to/box.html>`__ for the actual authenticated
encryption algorithm.
Each peer generates an ED25519 key-pair to use as a persistent
(long-term) id.
When two peers establish a TCP connection, they first each generate an
ephemeral ED25519 key-pair to use for this session, and send each other
their respective ephemeral public keys. This happens in the clear.
They then each compute the shared secret. The shared secret is the
multiplication of the peer's ephemeral private key by the other peer's
ephemeral public key. The result is the same for both peers by the magic
of `elliptic
curves <https://en.wikipedia.org/wiki/Elliptic_curve_cryptography>`__.
The shared secret is used as the symmetric key for the encryption
algorithm.
The two ephemeral public keys are sorted to establish a canonical order.
Then a 24-byte nonce is generated by concatenating the public keys and
hashing them with Ripemd160. Note Ripemd160 produces 20byte hashes, so
the nonce ends with four 0s.
The nonce is used to seed the encryption - it is critical that the same
nonce never be used twice with the same private key. For convenience,
the last bit of the nonce is flipped, giving us two nonces: one for
encrypting our own messages, one for decrypting our peer's. Which ever
peer has the higher public key uses the "bit-flipped" nonce for
encryption.
Now, a challenge is generated by concatenating the ephemeral public keys
and taking the SHA256 hash.
Each peer signs the challenge with their persistent private key, and
sends the other peer an AuthSigMsg, containing their persistent public
key and the signature. On receiving an AuthSigMsg, the peer verifies the
signature.
The peers are now authenticated.
All future communications can now be encrypted using the shared secret
and the generated nonces, where each nonce is incremented by one each
time it is used. The communications maintain Perfect Forward Secrecy, as
the persistent key pair was not used for generating secrets - only for
authenticating.
Caveat
------
This system is still vulnerable to a Man-In-The-Middle attack if the
persistent public key of the remote node is not known in advance. The
only way to mitigate this is with a public key authentication system,
such as the Web-of-Trust or Certificate Authorities. In our case, we can
use the blockchain itself as a certificate authority to ensure that we
are connected to at least one validator.
Additional Reading
------------------
- `Implementation <https://github.com/tendermint/go-p2p/blob/master/secret_connection.go#L49>`__
- `Original STS paper by Whitfield Diffie, Paul C. van Oorschot and
Michael J.
Wiener <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.216.6107&rep=rep1&type=pdf>`__
- `Further work on secret
handshakes <https://dominictarr.github.io/secret-handshake-paper/shs.pdf>`__

+ 20
- 0
docs/specification.rst View File

@ -0,0 +1,20 @@
#############
Specification
#############
Here you'll find details of the Tendermint specification. See `the spec repo <https://github.com/tendermint/spec>`__ for upcoming material. Tendermint's types are produced by `godoc <https://godoc.org/github.com/tendermint/tendermint/types>`__
.. toctree::
:maxdepth: 2
block-structure.rst
byzantine-consensus-algorithm.rst
configuration.rst
fast-sync.rst
genesis.rst
light-client-protocol.rst
merkle.rst
rpc.rst
secure-p2p.rst
validators.rst
wire-protocol.rst

+ 0
- 168
docs/specs/block-structure.md View File

@ -1,168 +0,0 @@
# Block Structure
The tendermint consensus engine records all agreements by a supermajority of
nodes into a blockchain, which is replicated among all nodes. This blockchain
is accessible via various rpc endpoints, mainly `/block?height=` to get the full
block, as well as `/blockchain?minHeight=_&maxHeight=_` to get a list of headers.
But what exactly is stored in these blocks?
### Block
A [Block](https://godoc.org/github.com/tendermint/tendermint/types#Block) contains:
* a [Header](#header) contains merkle hashes for various chain states
* the [Data](https://godoc.org/github.com/tendermint/tendermint/types#Data) is all transactions which are to be processed
* the [LastCommit](#commit) > 2/3 signatures for the last block
The signatures returned along with block `H` are those validating block `H-1`.
This can be a little confusing, but we must also consider that the
`Header` also contains the `LastCommitHash`.
It would be impossible for a Header to include the commits that sign it, as it
would cause an infinite loop here. But when we get block `H`, we find
`Header.LastCommitHash`, which must match the hash of `LastCommit`.
### Header
The [Header](https://godoc.org/github.com/tendermint/tendermint/types#Header) contains lots of information (follow
link for up-to-date info). Notably, it maintains the `Height`, the `LastBlockID`
(to make it a chain), and hashes of the data, the app state, and the validator set.
This is important as the only item that is signed by the validators is the `Header`,
and all other data must be validated against one of the merkle hashes in the `Header`.
The `DataHash` can provide a nice check on the [Data](https://godoc.org/github.com/tendermint/tendermint/types#Data)
returned in this same block. If you are subscribed to new blocks, via tendermint RPC, in order to display or process the new transactions
you should at least validate that the `DataHash` is valid.
If it is important to verify autheniticity, you must wait for the `LastCommit` from the next block to make sure the block header (including `DataHash`) was properly signed.
The `ValidatorHash` contains a hash of the current
[Validators](https://godoc.org/github.com/tendermint/tendermint/types#Validator). Tracking all changes in the
validator set is complex, but a client can quickly compare this hash
with the [hash of the currently known validators](https://godoc.org/github.com/tendermint/tendermint/types#ValidatorSet.Hash)
to see if there have been changes.
The `AppHash` serves as the basis for validating any merkle proofs that come
from the [ABCI application](https://github.com/tendermint/abci). It represents
the state of the actual application, rather that the state of the blockchain
itself. This means it's necessary in order to perform any business logic,
such as verifying and account balance.
**Note** After the transactions are committed to a block, they still need to
be processed in a separate step, which happens between the blocks. If you
find a given transaction in the block at height `H`, the effects of running
that transaction will be first visible in the `AppHash` from the block
header at height `H+1`.
Like the `LastCommit` issue, this is a requirement of the
immutability of the block chain, as the application only applies transactions
*after* they are commited to the chain.
### Commit
The [Commit](https://godoc.org/github.com/tendermint/tendermint/types#Commit) contains a set of
[Votes](https://godoc.org/github.com/tendermint/tendermint/types#Vote) that were made by the validator set to
reach consensus on this block. This is the key to the security in any PoS
system, and actually no data that cannot be traced back to a block header
with a valid set of Votes can be trusted. Thus, getting the Commit data
and verifying the votes is extremely important.
As mentioned above, in order to find the `precommit votes` for block header `H`,
we need to query block `H+1`. Then we need to check the votes, make sure they
really are for that block, and properly formatted. Much of this code is implemented
in Go in the [light-client](https://github.com/tendermint/light-client) package.
If you look at the code, you will notice that we need to provide the `chainID`
of the blockchain in order to properly calculate the votes. This is to protect
anyone from swapping votes between chains to fake (or frame) a validator.
Also note that this `chainID` is in the `genesis.json` from _Tendermint_,
not the `genesis.json` from the basecoin app ([that is a different chainID...](https://github.com/tendermint/basecoin/issues/32)).
Once we have those votes,
and we calculated the proper [sign bytes](https://godoc.org/github.com/tendermint/tendermint/types#Vote.WriteSignBytes)
using the chainID and a [nice helper function](https://godoc.org/github.com/tendermint/tendermint/types#SignBytes),
we can verify them. The light client is responsible for maintaining a set of
validators that we trust. Each vote only stores the validators `Address`, as well
as the `Signature`. Assuming we have a local copy of the trusted validator set,
we can look up the `Public Key` of the validator given its `Address`, then
verify that the `Signature` matches the `SignBytes` and `Public Key`.
Then we sum up the total voting power of all validators, whose votes fulfilled
all these stringent requirements. If the total number of voting power for a single block is greater
than 2/3 of all voting power, then we can finally trust the
block header, the AppHash, and the proof we got from the ABCI application.
#### Vote Sign Bytes
The `sign-bytes` of a vote is produced by taking a [`stable-json`](https://github.com/substack/json-stable-stringify)-like deterministic JSON [`wire`](/docs/specs/wire-protocol) encoding of the vote (excluding the `Signature` field), and wrapping it with `{"chain_id":"my_chain","vote":...}`.
For example, a precommit vote might have the following `sign-bytes`:
```json
{"chain_id":"my_chain","vote":{"block_hash":"611801F57B4CE378DF1A3FFF1216656E89209A99","block_parts_header":{"hash":"B46697379DBE0774CC2C3B656083F07CA7E0F9CE","total":123},"height":1234,"round":1,"type":2}}
```
### Block Hash
The [block hash](https://godoc.org/github.com/tendermint/tendermint/types#Block.Hash) is the [Simple Tree hash](Merkle-Trees#simple-tree-with-dictionaries) of the fields of the block `Header` encoded as a list of `KVPair`s.
### Transaction
A transaction is any sequence of bytes. It is up to your [ABCI](https://github.com/tendermint/abci) application to accept or reject transactions.
### BlockID
Many of these data structures refer to the [BlockID](https://godoc.org/github.com/tendermint/tendermint/types#BlockID),
which is the `BlockHash` (hash of the block header, also referred to by the next block)
along with the `PartSetHeader`. The `PartSetHeader` is explained below and is used internally
to orchestrate the p2p propogation. For clients, it is basically opaque bytes,
but they must match for all votes.
### PartSetHeader
The [PartSetHeader](https://godoc.org/github.com/tendermint/tendermint/types#PartSetHeader) contains the total number of pieces in a [PartSet](https://godoc.org/github.com/tendermint/tendermint/types#PartSet), and the Merkle root hash of those pieces.
### PartSet
PartSet is used to split a byteslice of data into parts (pieces) for transmission.
By splitting data into smaller parts and computing a Merkle root hash on the list,
you can verify that a part is legitimately part of the complete data, and the
part can be forwarded to other peers before all the parts are known. In short,
it's a fast way to securely propagate a large chunk of data (like a block) over a gossip network.
PartSet was inspired by the LibSwift project.
Usage:
```go
data := RandBytes(2 << 20) // Something large
partSet := NewPartSetFromData(data)
partSet.Total() // Total number of 4KB parts
partSet.Count() // Equal to the Total, since we already have all the parts
partSet.Hash() // The Merkle root hash
partSet.BitArray() // A BitArray of partSet.Total() 1's
header := partSet.Header() // Send this to the peer
header.Total // Total number of parts
header.Hash // The merkle root hash
// Now we'll reconstruct the data from the parts
partSet2 := NewPartSetFromHeader(header)
partSet2.Total() // Same total as partSet.Total()
partSet2.Count() // Zero, since this PartSet doesn't have any parts yet.
partSet2.Hash() // Same hash as in partSet.Hash()
partSet2.BitArray() // A BitArray of partSet.Total() 0's
// In a gossip network the parts would arrive in arbitrary order, perhaps
// in response to explicit requests for parts, or optimistically in response
// to the receiving peer's partSet.BitArray().
for !partSet2.IsComplete() {
part := receivePartFromGossipNetwork()
added, err := partSet2.AddPart(part)
if err != nil {
// A wrong part,
// the merkle trail does not hash to partSet2.Hash()
} else if !added {
// A duplicate part already received
}
}
data2, _ := ioutil.ReadAll(partSet2.GetReader())
bytes.Equal(data, data2) // true
```

+ 0
- 191
docs/specs/byzantine-consensus-algorithm.md View File

@ -1,191 +0,0 @@
# Byzantine Consensus Algorithm
_The draft 0.6 whitepaper is outdated. The new algorithm is detailed below. See [revisions](#revisions)_
## Terms
- The network is composed of optionally connected _nodes_. Nodes directly connected to a particular node are called _peers_.
- The consensus process in deciding the next block (at some _height_ `H`) is composed of one or many _rounds_.
- `NewHeight`, `Propose`, `Prevote`, `Precommit`, and `Commit` represent state machine states of a round. (aka `RoundStep` or just "step").
- A node is said to be _at_ a given height, round, and step, or at `(H,R,S)`, or at `(H,R)` in short to omit the step.
- To _prevote_ or _precommit_ something means to broadcast a [prevote vote](https://godoc.org/github.com/tendermint/tendermint/types#Vote) or [first precommit vote](https://godoc.org/github.com/tendermint/tendermint/types#FirstPrecommit) for something.
- A vote _at_ `(H,R)` is a vote signed with the bytes for `H` and `R` included in its [`sign-bytes`](/docs/specs/block-structure#vote-sign-bytes).
- _+2/3_ is short for "more than 2/3"
- _1/3+_ is short for "1/3 or more"
- A set of +2/3 of prevotes for a particular block or `<nil>` at `(H,R)` is called a _proof-of-lock-change_ or _PoLC_ for short.
## State Machine Overview
At each height of the blockchain a round-based protocol is run to determine
the next block. Each round is composed of three _steps_ (`Propose`, `Prevote`, and
`Precommit`), along with two special steps `Commit` and `NewHeight`.
In the optimal scenario, the order of steps is:
```
NewHeight -> (Propose -> Prevote -> Precommit)+ -> Commit -> NewHeight ->...
```
The sequence `(Propose -> Prevote -> Precommit)` is called a _round_. There may be more than one round required to commit a block at a given height. Examples for why more rounds may be required include:
- The designated proposer was not online.
- The block proposed by the designated proposer was not valid.
- The block proposed by the designated proposer did not propagate in time.
- The block proposed was valid, but +2/3 of prevotes for the proposed block were not received in time for enough validator nodes by the time they reached the `Precommit` step. Even though +2/3 of prevotes are necessary to progress to the next step, at least one validator may have voted `<nil>` or maliciously voted for something else.
- The block proposed was valid, and +2/3 of prevotes were received for enough nodes, but +2/3 of precommits for the proposed block were not received for enough validator nodes.
Some of these problems are resolved by moving onto the next round & proposer. Others are resolved by increasing certain round timeout parameters over each successive round.
## State Machine Diagram
```
+-------------------------------------+
v |(Wait til `CommmitTime+timeoutCommit`)
+-----------+ +-----+-----+
+----------> | Propose +--------------+ | NewHeight |
| +-----------+ | +-----------+
| | ^
|(Else, after timeoutPrecommit) v |
+-----+-----+ +-----------+ |
| Precommit | <------------------------+ Prevote | |
+-----+-----+ +-----------+ |
|(When +2/3 Precommits for block found) |
v |
+--------------------------------------------------------------------+
| Commit |
| |
| * Set CommitTime = now; |
| * Wait for block, then stage/save/commit block; |
+--------------------------------------------------------------------+
```
## Background Gossip
A node may not have a corresponding validator private key, but it nevertheless plays an active role in the consensus process by relaying relevant meta-data, proposals, blocks, and votes to its peers. A node that has the private keys of an active validator and is engaged in signing votes is called a _validator-node_. All nodes (not just validator-nodes) have an associated state (the current height, round, and step) and work to make progress.
Between two nodes there exists a `Connection`, and multiplexed on top of this connection are fairly throttled `Channel`s of information. An epidemic gossip protocol is implemented among some of these channels to bring peers up to speed on the most recent state of consensus. For example,
- Nodes gossip `PartSet` parts of the current round's proposer's proposed block. A LibSwift inspired algorithm is used to quickly broadcast blocks across the gossip network.
- Nodes gossip prevote/precommit votes. A node NODE_A that is ahead of NODE_B can send NODE_B prevotes or precommits for NODE_B's current (or future) round to enable it to progress forward.
- Nodes gossip prevotes for the proposed PoLC (proof-of-lock-change) round if one is proposed.
- Nodes gossip to nodes lagging in blockchain height with block [commits](https://godoc.org/github.com/tendermint/tendermint/types#Commit) for older blocks.
- Nodes opportunistically gossip `HasVote` messages to hint peers what votes it already has.
- Nodes broadcast their current state to all neighboring peers. (but is not gossiped further)
There's more, but let's not get ahead of ourselves here.
## Proposals
A proposal is signed and published by the designated proposer at each round. The proposer is chosen by a deterministic and non-choking round robin selection algorithm that selects proposers in proportion to their voting power. (see [implementation](https://github.com/tendermint/tendermint/blob/develop/types/validator_set.go))
A proposal at `(H,R)` is composed of a block and an optional latest `PoLC-Round < R` which is included iff the proposer knows of one. This hints the network to allow nodes to unlock (when safe) to ensure the liveness property.
## State Machine Spec
### Propose Step (height:H,round:R)
Upon entering `Propose`:
- The designated proposer proposes a block at `(H,R)`.
The `Propose` step ends:
- After `timeoutProposeR` after entering `Propose`. --> goto `Prevote(H,R)`
- After receiving proposal block and all prevotes at `PoLC-Round`. --> goto `Prevote(H,R)`
- After [common exit conditions](#common-exit-conditions)
### Prevote Step (height:H,round:R)
Upon entering `Prevote`, each validator broadcasts its prevote vote.
- First, if the validator is locked on a block since `LastLockRound` but now has a PoLC for something else at round `PoLC-Round` where `LastLockRound < PoLC-Round < R`, then it unlocks.
- If the validator is still locked on a block, it prevotes that.
- Else, if the proposed block from `Propose(H,R)` is good, it prevotes that.
- Else, if the proposal is invalid or wasn't received on time, it prevotes `<nil>`.
The `Prevote` step ends:
- After +2/3 prevotes for a particular block or `<nil>`. --> goto `Precommit(H,R)`
- After `timeoutPrevote` after receiving any +2/3 prevotes. --> goto `Precommit(H,R)`
- After [common exit conditions](#common-exit-conditions)
### Precommit Step (height:H,round:R)
Upon entering `Precommit`, each validator broadcasts its precommit vote.
- If the validator has a PoLC at `(H,R)` for a particular block `B`, it (re)locks (or changes lock to) and precommits `B` and sets `LastLockRound = R`.
- Else, if the validator has a PoLC at `(H,R)` for `<nil>`, it unlocks and precommits `<nil>`.
- Else, it keeps the lock unchanged and precommits `<nil>`.
A precommit for `<nil>` means "I didn’t see a PoLC for this round, but I did get +2/3 prevotes and waited a bit".
The Precommit step ends:
- After +2/3 precommits for `<nil>`. --> goto `Propose(H,R+1)`
- After `timeoutPrecommit` after receiving any +2/3 precommits. --> goto `Propose(H,R+1)`
- After [common exit conditions](#common-exit-conditions)
#### common exit conditions
- After +2/3 precommits for a particular block. --> goto `Commit(H)`
- After any +2/3 prevotes received at `(H,R+x)`. --> goto `Prevote(H,R+x)`
- After any +2/3 precommits received at `(H,R+x)`. --> goto `Precommit(H,R+x)`
### Commit Step (height:H)
- Set `CommitTime = now()`
- Wait until block is received. --> goto `NewHeight(H+1)`
### NewHeight Step (height:H)
- Move `Precommits` to `LastCommit` and increment height.
- Set `StartTime = CommitTime+timeoutCommit`
- Wait until `StartTime` to receive straggler commits. --> goto `Propose(H,0)`
## Proofs
### Proof of Safety
Assume that at most -1/3 of the voting power of validators is byzantine. If a validator commits block `B` at round `R`, it's because it saw +2/3 of precommits at round `R`. This implies that 1/3+ of honest nodes are still locked at round `R' > R`. These locked validators will remain locked until they see a PoLC at `R' > R`, but this won't happen because 1/3+ are locked and honest, so at most -2/3 are available to vote for anything other than `B`.
### Proof of Liveness
If 1/3+ honest validators are locked on two different blocks from different rounds, a proposers' `PoLC-Round` will eventually cause nodes locked from the earlier round to unlock. Eventually, the designated proposer will be one that is aware of a PoLC at the later round. Also, `timeoutProposalR` increments with round `R`, while the size of a proposal are capped, so eventually the network is able to "fully gossip" the whole proposal (e.g. the block & PoLC).
### Proof of Fork Accountability
Define the JSet (justification-vote-set) at height `H` of a validator `V1` to be all the votes signed by the validator at `H` along with justification PoLC prevotes for each lock change. For example, if `V1` signed the following precommits: `Precommit(B1 @ round 0)`, `Precommit(<nil> @ round 1)`, `Precommit(B2 @ round 4)` (note that no precommits were signed for rounds 2 and 3, and that's ok), `Precommit(B1 @ round 0)` must be justified by a PoLC at round 0, and `Precommit(B2 @ round 4)` must be justified by a PoLC at round 4; but the precommit for `<nil>` at round 1 is not a lock-change by definition so the JSet for `V1` need not include any prevotes at round 1, 2, or 3 (unless `V1` happened to have prevoted for those rounds).
Further, define the JSet at height `H` of a set of validators `VSet` to be the union of the JSets for each validator in `VSet`. For a given commit by honest validators at round `R` for block `B` we can construct a JSet to justify the commit for `B` at `R`.
We say that a JSet _justifies_ a commit at `(H,R)` if all the committers (validators in the commit-set) are each justified in the JSet with no duplicitous vote signatures (by the committers).
- **Lemma**: When a fork is detected by the existence of two conflicting [commits](/docs/specs/validators#commiting-a-block), the union of the JSets for both commits (if they can be compiled) must include double-signing by at least 1/3+ of the validator set. **Proof**: The commit cannot be at the same round, because that would immediately imply double-signing by 1/3+. Take the union of the JSets of both commits. If there is no double-signing by at least 1/3+ of the validator set in the union, then no honest validator could have precommitted any different block after the first commit. Yet, +2/3 did. Reductio ad absurdum.
As a corollary, when there is a fork, an external process can determine the blame by requiring each validator to justify all of its round votes. Either we will find 1/3+ who cannot justify at least one of their votes, and/or, we will find 1/3+ who had double-signed.
### Alternative algorithm
Alternatively, we can take the JSet of a commit to be the "full commit". That is, if light clients and validators do not consider a block to be committed unless the JSet of the commit is also known, then we get the desirable property that if there ever is a fork (e.g. there are two conflicting "full commits"), then 1/3+ of the validators are immediately punishable for double-signing.
There are many ways to ensure that the gossip network efficiently share the JSet of a commit. One solution is to add a new message type that tells peers that this node has (or does not have) a +2/3 majority for B (or <nil>) at (H,R), and a bitarray of which votes contributed towards that majority. Peers can react by responding with appropriate votes.
We will implement such an algorithm for the next iteration of the Tendermint consensus protocol.
Other potential improvements include adding more data in votes such as the last known PoLC round that caused a lock change, and the last voted round/step (or, we may require that validators not skip any votes). This may make JSet verification/gossip logic easier to implement.
### Censorship Attacks
Due to the definition of a block [commit](/docs/specs/validators#commiting-a-block), any 1/3+ coalition of validators can halt the blockchain by not broadcasting their votes. Such a coalition can also censor particular transactions by rejecting blocks that include these transactions, though this would result in a significant proportion of block proposals to be rejected, which would slow down the rate of block commits of the blockchain, reducing its utility and value. The malicious coalition might also broadcast votes in a trickle so as to grind blockchain block commits to a near halt, or engage in any combination of these attacks.
If a global active adversary were also involved, it can partition the network in such a way that it may appear that the wrong subset of validators were responsible for the slowdown. This is not just a limitation of Tendermint, but rather a limitation of all consensus protocols whose network is potentially controlled by an active adversary.
### Overcoming Forks and Censorship Attacks
For these types of attacks, a subset of the validators through external means
should coordinate to sign a reorg-proposal that chooses a fork (and any evidence
thereof) and the initial subset of validators with their signatures. Validators
who sign such a reorg-proposal forego its collateral on all other forks.
Clients should verify the signatures on the reorg-proposal, verify any evidence,
and make a judgement or prompt the end-user for a decision. For example, a
phone wallet app may prompt the user with a security warning, while a
refrigerator may accept any reorg-proposal signed by +½ of the original
validators.
No non-synchronous Byzantine fault-tolerant algorithm can come to consensus when
⅓+ of validators are dishonest, yet a fork assumes that ⅓+ of validators have
already been dishonest by double-signing or lock-changing without justification.
So, signing the reorg-proposal is a coordination problem that cannot be solved
by any non-synchronous protocol (i.e. automatically, and without making
assumptions about the reliability of the underlying network). It must be
provided by means external to the weakly-synchronous Tendermint consensus
algorithm. For now, we leave the problem of reorg-proposal coordination to
human coordination via internet media. Validators must take care to ensure that
there are no significant network partitions, to avoid situations where two
conflicting reorg-proposals are signed.
Assuming that the external coordination medium and protocol is robust, it follows that forks are less of a concern than [censorship attacks](#censorship-attacks).

+ 0
- 36
docs/specs/configuration.md View File

@ -1,36 +0,0 @@
# Configuration
TendermintCore can be configured via a TOML file in `$TMHOME/config.toml`.
Some of these parameters can be overridden by command-line flags.
### Config parameters
The main config parameters are defined [here](https://github.com/tendermint/tendermint/blob/master/config/config.go).
* `abci`: ABCI transport (socket | grpc). _Default_: `socket`
* `db_backend`: Database backend for the blockchain and TendermintCore state. `leveldb` or `memdb`. _Default_: `"leveldb"`
* `db_dir`: Database dir. _Default_: `"$TMHOME/data"`
* `fast_sync`: Whether to sync faster from the block pool. _Default_: `true`
* `genesis_file`: The location of the genesis file. _Default_: `"$TMHOME/genesis.json"`
* `log_level`: _Default_: `"state:info,*:error"`
* `moniker`: Name of this node. _Default_: `"anonymous"`
* `priv_validator_file`: Validator private key file. _Default_: `"$TMHOME/priv_validator.json"`
* `prof_laddr`: Profile listen address. _Default_: `""`
* `proxy_app`: The ABCI app endpoint. _Default_: `"tcp://127.0.0.1:46658"`
* `consensus.max_block_size_txs`: Maximum number of block txs. _Default_: `10000`
* `consensus.timeout_*`: Various consensus timeout parameters **TODO**
* `consensus.wal_file`: Consensus state WAL. _Default_: `"$TMHOME/data/cswal"`
* `consensus.wal_light`: Whether to use light-mode for Consensus state WAL. _Default_: `false`
* `mempool.*`: Various mempool parameters **TODO**
* `p2p.addr_book_file`: Peer address book. _Default_: `"$TMHOME/addrbook.json"`. **NOT USED**
* `p2p.laddr`: Node listen address. (0.0.0.0:0 means any interface, any port). _Default_: `"0.0.0.0:46656"`
* `p2p.pex`: Enable Peer-Exchange (dev feature). _Default_: `false`
* `p2p.seeds`: Comma delimited host:port seed nodes. _Default_: `""`
* `p2p.skip_upnp`: Skip UPNP detection. _Default_: `false`
* `rpc.grpc_laddr`: GRPC listen address (BroadcastTx only). Port required. _Default_: `""`
* `rpc.laddr`: RPC listen address. Port required. _Default_: `"0.0.0.0:46657"`
* `rpc.unsafe`: Enabled unsafe rpc methods. _Default_: `true`

+ 0
- 13
docs/specs/fast-sync.md View File

@ -1,13 +0,0 @@
# Fast Sync
## Background
In a proof of work blockchain, syncing with the chain is the same process as staying up-to-date with the consensus: download blocks, and look for the one with the most total work. In proof-of-stake, the consensus process is more complex, as it involves rounds of communication between the nodes to determine what block should be committed next. Using this process to sync up with the blockchain from scratch can take a very long time. It's much faster to just download blocks and check the merkle tree of validators than to run the real-time consensus gossip protocol.
## Fast Sync
To support faster syncing, tendermint offers a `fast-sync` mode, which is enabled by default, and can be toggled in the `config.toml` or via `--fast_sync=false`.
In this mode, the tendermint daemon will sync hundreds of times faster than if it used the real-time consensus process. Once caught up, the daemon will switch out of fast sync and into the normal consensus mode. After running for some time, the node is considered `caught up` if it has at least one peer and it's height is at least as high as the max reported peer height. See [the IsCaughtUp method](https://github.com/tendermint/tendermint/blob/b467515719e686e4678e6da4e102f32a491b85a0/blockchain/pool.go#L128).
If we're lagging sufficiently, we should go back to fast syncing, but this is an open issue: https://github.com/tendermint/tendermint/issues/129

+ 0
- 61
docs/specs/genesis.md View File

@ -1,61 +0,0 @@
# Genesis
The genesis.json file in `$TMROOT` defines the initial TendermintCore state upon genesis of the blockchain ([see definition](https://github.com/tendermint/tendermint/blob/master/types/genesis.go)).
NOTE: This does not (yet) specify the application state (e.g. initial distribution of tokens). Currently we leave it up to the application to load the initial application genesis state. In the future, we may include genesis SetOption messages that get passed from TendermintCore to the app upon genesis.
### Fields
* `genesis_time`: Official time of blockchain start.
* `chain_id`: ID of the blockchain. This must be unique for every blockchain. If your testnet blockchains do not have unique chain IDs, you will have a bad time.
* `validators`:
* `pub_key`: The first element specifies the pub_key type. 1 == Ed25519. The second element are the pubkey bytes.
* `amount`: The validator's voting power.
* `name`: Name of the validator (optional).
* `app_hash`: The expected application hash (as returned by the `Commit` ABCI message) upon genesis. If the app's hash does not match, a warning message is printed.
### Sample genesis.json
This example is from the Basecoin mintnet example:
```json
{
"genesis_time": "2016-02-05T06:02:31.526Z",
"chain_id": "chain-tTH4mi",
"validators": [
{
"pub_key": [
1,
"9BC5112CB9614D91CE423FA8744885126CD9D08D9FC9D1F42E552D662BAA411E"
],
"amount": 1,
"name": "mach1"
},
{
"pub_key": [
1,
"F46A5543D51F31660D9F59653B4F96061A740FF7433E0DC1ECBC30BE8494DE06"
],
"amount": 1,
"name": "mach2"
},
{
"pub_key": [
1,
"0E7B423C1635FD07C0FC3603B736D5D27953C1C6CA865BB9392CD79DE1A682BB"
],
"amount": 1,
"name": "mach3"
},
{
"pub_key": [
1,
"4F49237B9A32EB50682EDD83C48CE9CDB1D02A7CFDADCFF6EC8C1FAADB358879"
],
"amount": 1,
"name": "mach4"
}
],
"app_hash": "15005165891224E721CB664D15CB972240F5703F"
}
```

+ 0
- 15
docs/specs/light-client-protocol.md View File

@ -1,15 +0,0 @@
# Light Client Protocol
Light clients are an important part of the complete blockchain system for most applications. Tendermint provides unique speed and security properties for light client applications.
See our developing [light-client repository](https://github.com/tendermint/light-client).
## Overview
The objective of the light client protocol is to get a [commit](/docs/specs/validators#committing-a-block) for a recent [block hash](/docs/specs/block-structure#block-hash) where the commit includes a majority of signatures from the last known validator set. From there, all the application state is verifiable with [merkle proofs](/docs/specs/merkle-trees#iavl-tree).
## Properties
- You get the full collateralized security benefits of Tendermint; No need to wait for confirmations.
- You get the full speed benefits of Tendermint; Transactions commit instantly.
- You can get the most recent version of the application state non-interactively (without committing anything to the blockchain). For example, this means that you can get the most recent value of a name from the name-registry without worrying about fork censorship attacks, without posting a commit and waiting for confirmations. It's fast, secure, and free!

+ 0
- 45
docs/specs/merkle.md View File

@ -1,45 +0,0 @@
# Merkle
For an overview of Merkle trees, see [wikipedia](https://en.wikipedia.org/wiki/Merkle_tree).
There are two types of Merkle trees used in Tendermint.
- [`IAVL+ Tree`](#iavl-tree): An immutable self-balancing binary tree for persistent application state
- [`Simple Tree`](#simple-tree): A simple compact binary tree for a static list of items
## IAVL+ Tree
The purpose of this data structure is to provide persistent storage for key-value pairs (e.g. account state, name-registrar data, and per-contract data) such that a deterministic merkle root hash can be computed. The tree is balanced using a variant of the [AVL algorithm](http://en.wikipedia.org/wiki/AVL_tree) so all operations are O(log(n)).
Nodes of this tree are immutable and indexed by its hash. Thus any node serves as an immutable snapshot which lets us stage uncommitted transactions from the mempool cheaply, and we can instantly roll back to the last committed state to process transactions of a newly committed block (which may not be the same set of transactions as those from the mempool).
In an AVL tree, the heights of the two child subtrees of any node differ by at most one. Whenever this condition is violated upon an update, the tree is rebalanced by creating O(log(n)) new nodes that point to unmodified nodes of the old tree. In the original AVL algorithm, inner nodes can also hold key-value pairs. The AVL+ algorithm (note the plus) modifies the AVL algorithm to keep all values on leaf nodes, while only using branch-nodes to store keys. This simplifies the algorithm while minimizing the size of merkle proofs
In Ethereum, the analog is the [Patricia trie](http://en.wikipedia.org/wiki/Radix_tree). There are tradeoffs. Keys do not need to be hashed prior to insertion in IAVL+ trees, so this provides faster iteration in the key space which may benefit some applications. The logic is simpler to implement, requiring only two types of nodes -- inner nodes and leaf nodes. The IAVL+ tree is a binary tree, so merkle proofs are much shorter than the base 16 Patricia trie. On the other hand, while IAVL+ trees provide a deterministic merkle root hash, it depends on the order of updates. In practice this shouldn't be a problem, since you can efficiently encode the tree structure when serializing the tree contents.
## Simple Tree
For merkelizing smaller static lists, use the Simple Tree. The transactions and validation signatures of a block are hashed using this simple merkle tree logic.
If the number of items is not a power of two, the tree will not be full and some leaf nodes will be at different levels. Simple Tree tries to keep both sides of the tree the same size, but the left side may be one greater.
```
Simple Tree with 6 items Simple Tree with 7 items
* *
/ \ / \
/ \ / \
/ \ / \
/ \ / \
* * * *
/ \ / \ / \ / \
/ \ / \ / \ / \
/ \ / \ / \ / \
* h2 * h5 * * * h6
/ \ / \ / \ / \ / \
h0 h1 h3 h4 h0 h1 h2 h3 h4 h5
```
### Simple Tree with Dictionaries
The Simple Tree is used to merkelize a list of items, so to merkelize a (short) dictionary of key-value pairs, encode the dictionary as an ordered list of `KVPair` structs. The block hash is such a hash derived from all the fields of the block `Header`. The state hash is similarly derived.

+ 0
- 156
docs/specs/rpc.md View File

@ -1,156 +0,0 @@
# RPC
Tendermint supports the following RPC protocols:
* URI over HTTP
* JSONRPC over HTTP
* JSONRPC over websockets
Tendermint RPC is build using [our own RPC library](https://github.com/tendermint/tendermint/tree/master/rpc/lib). Documentation and tests for that library could be found at `tendermint/rpc/lib` directory.
### Configuration
Set the `laddr` config parameter under `[rpc]` table in the $TMHOME/config.toml file or the `--rpc.laddr` command-line flag to the desired protocol://host:port setting. Default: `tcp://0.0.0.0:46657`.
### Arguments
Arguments which expect strings or byte arrays may be passed as quoted strings, like `"abc"` or as `0x`-prefixed strings, like `0x616263`.
### URI/HTTP
Example request:
```bash
curl -s 'http://localhost:46657/broadcast_tx_sync?tx="abc"' | jq .
```
Response:
```json
{
"error": "",
"result": {
"hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
"log": "",
"data": "",
"code": 0
},
"id": "",
"jsonrpc": "2.0"
}
```
The first entry in the result-array (`96`) is the method this response correlates with. `96` refers to "ResultTypeBroadcastTx", see [responses.go](https://github.com/tendermint/tendermint/blob/master/rpc/core/types/responses.go) for a complete overview.
### JSONRPC/HTTP
JSONRPC requests can be POST'd to the root RPC endpoint via HTTP (e.g. `http://localhost:46657/`).
Example request:
```json
{
"method": "broadcast_tx_sync",
"jsonrpc": "2.0",
"params": [ "abc" ],
"id": "dontcare"
}
```
### JSONRPC/websockets
JSONRPC requests can be made via websocket. The websocket endpoint is at `/websocket`, e.g. `http://localhost:46657/websocket`. Asynchronous RPC functions like event `subscribe` and `unsubscribe` are only available via websockets.
### Endpoints
An HTTP Get request to the root RPC endpoint (e.g. `http://localhost:46657`) shows a list of available endpoints.
```
Available endpoints:
http://localhost:46657/abci_info
http://localhost:46657/dump_consensus_state
http://localhost:46657/genesis
http://localhost:46657/net_info
http://localhost:46657/num_unconfirmed_txs
http://localhost:46657/status
http://localhost:46657/unconfirmed_txs
http://localhost:46657/unsafe_flush_mempool
http://localhost:46657/unsafe_stop_cpu_profiler
http://localhost:46657/validators
Endpoints that require arguments:
http://localhost:46657/abci_query?path=_&data=_&prove=_
http://localhost:46657/block?height=_
http://localhost:46657/blockchain?minHeight=_&maxHeight=_
http://localhost:46657/broadcast_tx_async?tx=_
http://localhost:46657/broadcast_tx_commit?tx=_
http://localhost:46657/broadcast_tx_sync?tx=_
http://localhost:46657/commit?height=_
http://localhost:46657/dial_seeds?seeds=_
http://localhost:46657/subscribe?event=_
http://localhost:46657/tx?hash=_&prove=_
http://localhost:46657/unsafe_start_cpu_profiler?filename=_
http://localhost:46657/unsafe_write_heap_profile?filename=_
http://localhost:46657/unsubscribe?event=_
```
### tx
Returns a transaction matching the given transaction hash.
**Parameters**
1. hash - the transaction hash
2. prove - include a proof of the transaction inclusion in the block in the result (optional, default: false)
**Returns**
- `proof`: the `types.TxProof` object
- `tx`: `[]byte` - the transaction
- `tx_result`: the `abci.Result` object
- `index`: `int` - index of the transaction
- `height`: `int` - height of the block where this transaction was in
**Example**
```bash
curl -s 'http://localhost:46657/broadcast_tx_commit?tx="abc"' | jq .
# {
# "error": "",
# "result": {
# "hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
# "log": "",
# "data": "",
# "code": 0
# },
# "id": "",
# "jsonrpc": "2.0"
# }
curl -s 'http://localhost:46657/tx?hash=0x2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF' | jq .
# {
# "error": "",
# "result": {
# "proof": {
# "Proof": {
# "aunts": []
# },
# "Data": "YWJjZA==",
# "RootHash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
# "Total": 1,
# "Index": 0
# },
# "tx": "YWJjZA==",
# "tx_result": {
# "log": "",
# "data": "",
# "code": 0
# },
# "index": 0,
# "height": 52
# },
# "id": "",
# "jsonrpc": "2.0"
# }
```
### More Examples
See the various bash tests using curl in `test/`, and examples using the `Go` API in `rpc/client/`.

+ 0
- 33
docs/specs/secure-p2p.md View File

@ -1,33 +0,0 @@
# Secure P2P
The Tendermint p2p protocol uses an authenticated encryption scheme based on the [Station-to-Station Protocol](https://en.wikipedia.org/wiki/Station-to-Station_protocol). The implementation uses [golang's](https://godoc.org/golang.org/x/crypto/nacl/box) [nacl box](http://nacl.cr.yp.to/box.html) for the actual authenticated encryption algorithm.
Each peer generates an ED25519 key-pair to use as a persistent (long-term) id.
When two peers establish a TCP connection, they first each generate an ephemeral ED25519 key-pair to use for this session, and send each other their respective ephemeral public keys. This happens in the clear.
They then each compute the shared secret. The shared secret is the multiplication of the peer's ephemeral private key by the other peer's ephemeral public key. The result is the same for both peers by the magic of [elliptic curves](https://en.wikipedia.org/wiki/Elliptic_curve_cryptography). The shared secret is used as the symmetric key for the encryption algorithm.
The two ephemeral public keys are sorted to establish a canonical order. Then a 24-byte nonce is generated by concatenating the public keys and hashing them with Ripemd160. Note Ripemd160 produces 20byte hashes, so the nonce ends with four 0s.
The nonce is used to seed the encryption - it is critical that the same nonce never be used twice with the same private key. For convenience, the last bit of the nonce is flipped, giving us two nonces: one for encrypting our own messages, one for decrypting our peer's. Which ever peer has the higher public key uses the "bit-flipped" nonce for encryption.
Now, a challenge is generated by concatenating the ephemeral public keys and taking the SHA256 hash.
Each peer signs the challenge with their persistent private key, and sends the other peer an AuthSigMsg, containing their persistent public key and the signature. On receiving an AuthSigMsg, the peer verifies the signature.
The peers are now authenticated.
All future communications can now be encrypted using the shared secret and the generated nonces, where each nonce is incremented by one each time it is used. The communications maintain Perfect Forward Secrecy, as the persistent key pair was not used for generating secrets - only for authenticating.
Caveat
------
This system is still vulnerable to a Man-In-The-Middle attack if the persistent public key of the remote node is not known in advance. The only way to mitigate this is with a public key authentication system, such as the Web-of-Trust or Certificate Authorities. In our case, we can use the blockchain itself as a certificate authority to ensure that we are connected to at least one validator.
Links
------
- [Implementation](https://github.com/tendermint/go-p2p/blob/master/secret_connection.go#L49)
- [Original STS paper by Whitfield Diffie, Paul C. van Oorschot and Michael J. Wiener](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.216.6107&rep=rep1&type=pdf)
- [Further work on secret handshakes](https://dominictarr.github.io/secret-handshake-paper/shs.pdf)

+ 0
- 2
docs/specs/tendermint-types.md View File

@ -1,2 +0,0 @@
# types
see the [godoc version](https://godoc.org/github.com/tendermint/tendermint/types)

+ 0
- 21
docs/specs/validators.md View File

@ -1,21 +0,0 @@
# Validators
Validators are responsible for committing new blocks in the blockchain.
These validators participate in the consensus protocol by broadcasting _votes_ which contain cryptographic signatures signed by each validator's public key.
Some Proof-of-Stake consensus algorithms aim to create a "completely" decentralized system where all stakeholders (even those who are not always available online) participate in the committing of blocks. Tendermint has a different approach to block creation. Validators are expected to be online, and the set of validators is permissioned/curated by some external process. Proof-of-stake is not required, but can be implemented on top of Tendermint consensus. That is, validators may be required to post collateral on-chain, off-chain, or may not be required to post any collateral at all.
Validators have a cryptographic key-pair and an associated amount of "voting power". Voting power need not be the same.
## Becoming a Validator
There are two ways to become validator.
1. They can be pre-established in the [genesis state](/docs/specs/genesis)
2. The [ABCI app responds to the EndBlock message](https://github.com/tendermint/abci) with changes to the existing validator set.
## Committing a Block
_+2/3 is short for "more than 2/3"_
A block is committed when +2/3 of the validator set sign [precommit votes](/docs/specs/block-structure#vote) for that block at the same [round](/docs/specs/consensus). The +2/3 set of precommit votes is called a [_commit_](/docs/specs/block-structure#commit). While any +2/3 set of precommits for the same block at the same height&round can serve as validation, the canonical commit is included in the next block (see [LastCommit](/docs/specs/block-structure).

+ 0
- 119
docs/specs/wire-protocol.md View File

@ -1,119 +0,0 @@
# Wire Protocol
The [Tendermint wire protocol](https://github.com/tendermint/go-wire) encodes data in [c-style binary](#binary) and [JSON](#json) form.
## Supported types
- Primitive types
- `uint8` (aka `byte`), `uint16`, `uint32`, `uint64`
- `int8`, `int16`, `int32`, `int64`
- `uint`, `int`: variable length (un)signed integers
- `string`, `[]byte`
- `time`
- Derived types
- structs
- var-length arrays of a particular type
- fixed-length arrays of a particular type
- interfaces: registered union types preceded by a `type byte`
- pointers
## Binary
**Fixed-length primitive types** are encoded with 1,2,3, or 4 big-endian bytes.
- `uint8` (aka `byte`), `uint16`, `uint32`, `uint64`: takes 1,2,3, and 4 bytes respectively
- `int8`, `int16`, `int32`, `int64`: takes 1,2,3, and 4 bytes respectively
- `time`: `int64` representation of nanoseconds since epoch
**Variable-length integers** are encoded with a single leading byte representing the length of the following big-endian bytes. For signed negative integers, the most significant bit of the leading byte is a 1.
- `uint`: 1-byte length prefixed variable-size (0 ~ 255 bytes) unsigned integers
- `int`: 1-byte length prefixed variable-size (0 ~ 127 bytes) signed integers
NOTE: While the number 0 (zero) is encoded with a single byte `x00`, the number 1 (one) takes two bytes to represent: `x0101`. This isn't the most efficient representation, but the rules are easier to remember.
| number | binary `uint` | binary `int` |
| ------------ | ------------- | ------------- |
| 0 | `x00` | `x00` |
| 1 | `x0101` | `x0101` |
| 2 | `x0102` | `x0102` |
| 256 | `x020100` | `x020100` |
| 2^(127*8)-1 | `x7FFFFF...` | `x7FFFFF...` |
| 2^(127*8) | `x800100...` | overflow |
| 2^(255*8)-1 | `xFFFFFF...` | overflow |
| -1 | n/a | `x8101` |
| -2 | n/a | `x8102` |
| -256 | n/a | `x820100` |
**Structures** are encoded by encoding the field values in order of declaration.
```go
type Foo struct {
MyString string
MyUint32 uint32
}
var foo = Foo{"626172", math.MaxUint32}
/* The binary representation of foo:
0103626172FFFFFFFF
0103: `int` encoded length of string, here 3
626172: 3 bytes of string "bar"
FFFFFFFF: 4 bytes of uint32 MaxUint32
*/
```
**Variable-length arrays** are encoded with a leading `int` denoting the length of the array followed by the binary representation of the items. **Fixed-length arrays** are similar but aren't preceded by the leading `int`.
```go
foos := []Foo{foo, foo}
/* The binary representation of foos:
01020103626172FFFFFFFF0103626172FFFFFFFF
0102: `int` encoded length of array, here 2
0103626172FFFFFFFF: the first `foo`
0103626172FFFFFFFF: the second `foo`
*/
foos := [2]Foo{foo, foo} // fixed-length array
/* The binary representation of foos:
0103626172FFFFFFFF0103626172FFFFFFFF
0103626172FFFFFFFF: the first `foo`
0103626172FFFFFFFF: the second `foo`
*/
```
**Interfaces** can represent one of any number of concrete types. The concrete types of an interface must first be declared with their corresponding `type byte`. An interface is then encoded with the leading `type byte`, then the binary encoding of the underlying concrete type.
NOTE: The byte `x00` is reserved for the `nil` interface value and `nil` pointer values.
```go
type Animal interface{}
type Dog uint32
type Cat string
RegisterInterface(
struct{ Animal }{}, // Convenience for referencing the 'Animal' interface
ConcreteType{Dog(0), 0x01}, // Register the byte 0x01 to denote a Dog
ConcreteType{Cat(""), 0x02}, // Register the byte 0x02 to denote a Cat
)
var animal Animal = Dog(02)
/* The binary representation of animal:
010102
01: the type byte for a `Dog`
0102: the bytes of Dog(02)
*/
```
**Pointers** are encoded with a single leading byte `x00` for `nil` pointers, otherwise encoded with a leading byte `x01` followed by the binary encoding of the value pointed to.
NOTE: It's easy to convert pointer types into interface types, since the `type byte` `x00` is always `nil`.
## JSON
The JSON codec is compatible with the [`binary`](#binary) codec, and is fairly intuitive if you're already familiar with golang's JSON encoding. Some quirks are noted below:
- variable-length and fixed-length bytes are encoded as uppercase hexadecimal strings
- interface values are encoded as an array of two items: `[type_byte, concrete_value]`
- times are encoded as rfc2822 strings

+ 356
- 0
docs/using-tendermint.rst View File

@ -0,0 +1,356 @@
Using Tendermint
================
This is a guide to using the ``tendermint`` program from the command
line. It assumes only that you have the ``tendermint`` binary installed
and have some rudimentary idea of what Tendermint and ABCI are.
You can see the help menu with ``tendermint --help``, and the version
number with ``tendermint version``.
Directory Root
--------------
The default directory for blockchain data is ``~/.tendermint``. Override
this by setting the ``TMROOT`` environment variable.
Initialize
----------
Initialize the root directory by running:
::
tendermint init
This will create a new private key (``priv_validator.json``), and a
genesis file (``genesis.json``) containing the associated public key.
This is all that's necessary to run a local testnet with one validator.
For more elaborate initialization, see our `testnet deployment
tool <https://github.com/tendermint/tools/tree/master/mintnet-kubernetes>`__.
Run
---
To run a tendermint node, use
::
tendermint node
By default, Tendermint will try to connect to a abci appliction on
`127.0.0.1:46658 <127.0.0.1:46658>`__. If you have the ``dummy`` ABCI
app installed, run it in another window. If you don't, kill tendermint
and run an in-process version with
::
tendermint node --proxy_app=dummy
After a few seconds you should see blocks start streaming in. Note that
blocks are produced regularly, even if there are no transactions. This
changes `with this pull
request <https://github.com/tendermint/tendermint/pull/584>`__.
Tendermint supports in-process versions of the dummy, counter, and nil
apps that ship as examples in the `ABCI
repository <https://github.com/tendermint/abci>`__. It's easy to compile
your own app in-process with tendermint if it's written in Go. If your
app is not written in Go, simply run it in another process, and use the
``--proxy_app`` flag to specify the address of the socket it is
listening on, for instance
::
tendermint node --proxy_app=/var/run/abci.sock
Transactions
------------
To send a transaction, use ``curl`` to make requests to the Tendermint
RPC server:
::
curl http://localhost:46657/broadcast_tx_commit?tx=\"abcd\"
For handling responses, we recommend you `install the jsonpp
tool <http://jmhodges.github.io/jsonpp/>`__ to pretty print the JSON.
We can see the chain's status at the ``/status`` end-point:
::
curl http://localhost:46657/status | jsonpp
and the ``latest_app_hash`` in particular:
::
curl http://localhost:46657/status | jsonpp | grep app_hash
Visit http://localhost:46657 in your browser to see the list of other
endpoints. Some take no arguments (like ``/status``), while others
specify the argument name and use ``_`` as a placeholder.
Reset
-----
**WARNING: UNSAFE** Only do this in development and only if you can
afford to lose all blockchain data!
To reset a blockchain, stop the node, remove the ``~/.tendermint/data``
directory and run
::
tendermint unsafe_reset_priv_validator
This final step is necessary to reset the ``priv_validator.json``, which
otherwise prevents you from making conflicting votes in the consensus
(something that could get you in trouble if you do it on a real
blockchain). If you don't reset the ``priv_validator.json``, your fresh
new blockchain will not make any blocks.
Configuration
-------------
Tendermint uses a ``config.toml`` for configutation. For details, see
`the documentation <./configuration.html>`__.
Notable options include the socket address of the application
(``proxy_app``), the listenting address of the tendermint peer
(``p2p.laddr``), and the listening address of the rpc server
(``rpc.laddr``).
Some fields from the config file can be overwritten with flags.
Broadcast API
-------------
Earlier, we used the ``broadcast_tx_commit`` endpoint to send a
transaction. When a transaction is sent to a tendermint node, it will
run via ``CheckTx`` against the application. If it passes ``CheckTx``,
it will be included in the mempool, broadcast to other peers, and
eventually included in a block.
Since there are multiple phases to processing a transaction, we offer
multiple endpoints to broadcast a transaction:
::
/broadcast_tx_async
/broadcast_tx_sync
/broadcast_tx_commit
These correspond to no-processing, processing through the mempool, and
processing through a block, respectively. That is,
``broadcast_tx_async``, will return right away without waiting to hear
if the transaction is even valid, while ``broadcast_tx_sync`` will
return with the result of running the transaction through ``CheckTx``.
Using ``broadcast_tx_commit`` will wait until the transaction is
committed in a block or until some timeout is reached, but will return
right away if the transaction does not pass ``CheckTx``. The return
value for ``broadcast_tx_commit`` includes two fields, ``check_tx`` and
``deliver_tx``, pertaining to the result of running the transaction
through those ABCI messages.
The benefit of using ``broadcast_tx_commit`` is that the request returns
after the transaction is committed (ie. included in a block), but that
can take on the order of a second. For a quick result, use
``broadcast_tx_sync``, but the transaction will not be committed until
later, and by that point its effect on the state may change.
Tendermint Networks
-------------------
When ``tendermint init`` is run, both a ``genesis.json`` and
``priv_validator.json`` are created in ``~/.tendermint``. The
``genesis.json`` might look like:
::
{
"app_hash": "",
"chain_id": "test-chain-HZw6TB",
"genesis_time": "0001-01-01T00:00:00.000Z",
"validators": [
{
"amount": 10,
"name": "",
"pub_key": [
1,
"5770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
]
}
]
}
And the ``priv_validator.json``:
::
{
"address": "4F4D895F882A18E1D1FC608D102601DA8D3570E5",
"last_height": 0,
"last_round": 0,
"last_signature": null,
"last_signbytes": "",
"last_step": 0,
"priv_key": [
1,
"F9FA3CD435BDAE54D0BCA8F1BC289D718C23D855C6DB21E8543F5E4F457E62805770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
],
"pub_key": [
1,
"5770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
]
}
The ``priv_validator.json`` actually contains a private key, and should
thus be kept absolutely secret; for now we work with the plain text.
Note the ``last_`` fields, which are used to prevent us from signing
conflicting messages.
Note also that the ``pub_key`` (the public key) in the
``priv_validator.json`` is also present in the ``genesis.json``.
The genesis file contains the list of public keys which may participate
in the consensus, and their corresponding voting power. Greater than 2/3
of the voting power must be active (ie. the corresponding private keys
must be producing signatures) for the consensus to make progress. In our
case, the genesis file contains the public key of our
``priv_validator.json``, so a tendermint node started with the default
root directory will be able to make new blocks, as we've already seen.
If we want to add more nodes to the network, we have two choices: we can
add a new validator node, who will also participate in the consensus by
proposing blocks and voting on them, or we can add a new non-validator
node, who will not participate directly, but will verify and keep up
with the consensus protocol.
Peers
~~~~~
To connect to peers on start-up, specify them in the ``config.toml`` or
on the command line.
For instance,
::
tendermint node --p2p.seeds "1.2.3.4:46656,5.6.7.8:46656"
Alternatively, you can use the ``/dial_seeds`` endpoint of the RPC to
specify peers for a running node to connect to:
::
curl --data-urlencode "seeds=[\"1.2.3.4:46656\",\"5.6.7.8:46656\"]" localhost:46657/dial_seeds
Additionally, the peer-exchange protocol can be enabled using the
``--pex`` flag, though this feature is `still under
development <https://github.com/tendermint/tendermint/issues/598>`__ If
``--pex`` is enabled, peers will gossip about known peers and form a
more resilient network.
Adding a Non-Validator
~~~~~~~~~~~~~~~~~~~~~~
Adding a non-validator is simple. Just copy the original
``genesis.json`` to ``~/.tendermint`` on the new machine and start the
node, specifying seeds as necessary. If no seeds are specified, the node
won't make any blocks, because it's not a validator, and it won't hear
about any blocks, because it's not connected to the other peer.
Adding a Validator
~~~~~~~~~~~~~~~~~~
The easiest way to add new validators is to do it in the
``genesis.json``, before starting the network. For instance, we could
make a new ``priv_validator.json``, and copy it's ``pub_key`` into the
above genesis.
We can generate a new ``priv_validator.json`` with the command:
::
tendermint gen_validator
Now we can update our genesis file. For instance, if the new
``priv_validator.json`` looks like:
::
{
"address": "AC379688105901436A34A65F185C115B8BB277A1",
"last_height": 0,
"last_round": 0,
"last_signature": null,
"last_signbytes": "",
"last_step": 0,
"priv_key": [
1,
"0D2ED337D748ADF79BE28559B9E59EBE1ABBA0BAFE6D65FCB9797985329B950C8F2B5AACAACC9FCE41881349743B0CFDE190DF0177744568D4E82A18F0B7DF94"
],
"pub_key": [
1,
"8F2B5AACAACC9FCE41881349743B0CFDE190DF0177744568D4E82A18F0B7DF94"
]
}
then the new ``genesis.json`` will be:
::
{
"app_hash": "",
"chain_id": "test-chain-HZw6TB",
"genesis_time": "0001-01-01T00:00:00.000Z",
"validators": [
{
"amount": 10,
"name": "",
"pub_key": [
1,
"5770B4DD55B3E08B7F5711C48B516347D8C33F47C30C226315D21AA64E0DFF2E"
]
},
{
"amount": 10,
"name": "",
"pub_key": [
1,
"8F2B5AACAACC9FCE41881349743B0CFDE190DF0177744568D4E82A18F0B7DF94"
]
}
]
}
Update the ``genesis.json`` in ``~/.tendermint``. Copy the genesis file
and the new ``priv_validator.json`` to the ``~/.tendermint`` on a new
machine.
Now run ``tendermint node`` on both machines, and use either
``--p2p.seeds`` or the ``/dial_seeds`` to get them to peer up. They
should start making blocks, and will only continue to do so as long as
both of them are online.
To make a Tendermint network that can tolerate one of the validators
failing, you need at least four validator nodes (> 2/3).
Updating validators in a live network is supported but must be
explicitly programmed by the application developer. See the `application
developers guide <./app-development.html>`__ for more
details.
Local Network
~~~~~~~~~~~~~
To run a network locally, say on a single machine, you must change the
``_laddr`` fields in the ``config.toml`` (or using the flags) so that
the listening addresses of the various sockets don't conflict.
Additionally, you must set ``addrbook_strict=false`` in the
``config.toml``, otherwise Tendermint's p2p library will deny making
connections to peers with the same IP address.

+ 44
- 0
docs/validators.rst View File

@ -0,0 +1,44 @@
Validators
==========
Validators are responsible for committing new blocks in the blockchain.
These validators participate in the consensus protocol by broadcasting
*votes* which contain cryptographic signatures signed by each
validator's public key.
Some Proof-of-Stake consensus algorithms aim to create a "completely"
decentralized system where all stakeholders (even those who are not
always available online) participate in the committing of blocks.
Tendermint has a different approach to block creation. Validators are
expected to be online, and the set of validators is permissioned/curated
by some external process. Proof-of-stake is not required, but can be
implemented on top of Tendermint consensus. That is, validators may be
required to post collateral on-chain, off-chain, or may not be required
to post any collateral at all.
Validators have a cryptographic key-pair and an associated amount of
"voting power". Voting power need not be the same.
Becoming a Validator
--------------------
There are two ways to become validator.
1. They can be pre-established in the `genesis
state <./genesis.html>`__
2. The `ABCI app responds to the EndBlock
message <https://github.com/tendermint/abci>`__ with changes to the
existing validator set.
Committing a Block
------------------
*+2/3 is short for "more than 2/3"*
A block is committed when +2/3 of the validator set sign `precommit
votes <./block-structure.html#vote>`__ for that block at the same
``round``. The +2/3 set of precommit votes is
called a `*commit* <./block-structure.html#commit>`__. While any
+2/3 set of precommits for the same block at the same height&round can
serve as validation, the canonical commit is included in the next block
(see `LastCommit <./block-structure.html>`__).

+ 172
- 0
docs/wire-protocol.rst View File

@ -0,0 +1,172 @@
Wire Protocol
=============
The `Tendermint wire protocol <https://github.com/tendermint/go-wire>`__
encodes data in `c-style binary <#binary>`__ and `JSON <#json>`__ form.
Supported types
---------------
- Primitive types
- ``uint8`` (aka ``byte``), ``uint16``, ``uint32``, ``uint64``
- ``int8``, ``int16``, ``int32``, ``int64``
- ``uint``, ``int``: variable length (un)signed integers
- ``string``, ``[]byte``
- ``time``
- Derived types
- structs
- var-length arrays of a particular type
- fixed-length arrays of a particular type
- interfaces: registered union types preceded by a ``type byte``
- pointers
Binary
------
**Fixed-length primitive types** are encoded with 1,2,3, or 4 big-endian
bytes. - ``uint8`` (aka ``byte``), ``uint16``, ``uint32``, ``uint64``:
takes 1,2,3, and 4 bytes respectively - ``int8``, ``int16``, ``int32``,
``int64``: takes 1,2,3, and 4 bytes respectively - ``time``: ``int64``
representation of nanoseconds since epoch
**Variable-length integers** are encoded with a single leading byte
representing the length of the following big-endian bytes. For signed
negative integers, the most significant bit of the leading byte is a 1.
- ``uint``: 1-byte length prefixed variable-size (0 ~ 255 bytes)
unsigned integers
- ``int``: 1-byte length prefixed variable-size (0 ~ 127 bytes) signed
integers
NOTE: While the number 0 (zero) is encoded with a single byte ``x00``,
the number 1 (one) takes two bytes to represent: ``x0101``. This isn't
the most efficient representation, but the rules are easier to remember.
+---------------+----------------+----------------+
| number | binary | binary ``int`` |
| | ``uint`` | |
+===============+================+================+
| 0 | ``x00`` | ``x00`` |
+---------------+----------------+----------------+
| 1 | ``x0101`` | ``x0101`` |
+---------------+----------------+----------------+
| 2 | ``x0102`` | ``x0102`` |
+---------------+----------------+----------------+
| 256 | ``x020100`` | ``x020100`` |
+---------------+----------------+----------------+
| 2^(127\ *8)-1 | ``x800100...`` | overflow |
| \| | | |
| ``x7FFFFF...` | | |
| ` | | |
| \| | | |
| ``x7FFFFF...` | | |
| ` | | |
| \| \| | | |
| 2^(127*\ 8) | | |
+---------------+----------------+----------------+
| 2^(255\*8)-1 |
| \| |
| ``xFFFFFF...` |
| ` |
| \| overflow |
| \| \| -1 \| |
| n/a \| |
| ``x8101`` \| |
| \| -2 \| n/a |
| \| ``x8102`` |
| \| \| -256 \| |
| n/a \| |
| ``x820100`` |
| \| |
+---------------+----------------+----------------+
**Structures** are encoded by encoding the field values in order of
declaration.
.. code:: go
type Foo struct {
MyString string
MyUint32 uint32
}
var foo = Foo{"626172", math.MaxUint32}
/* The binary representation of foo:
0103626172FFFFFFFF
0103: `int` encoded length of string, here 3
626172: 3 bytes of string "bar"
FFFFFFFF: 4 bytes of uint32 MaxUint32
*/
**Variable-length arrays** are encoded with a leading ``int`` denoting
the length of the array followed by the binary representation of the
items. **Fixed-length arrays** are similar but aren't preceded by the
leading ``int``.
.. code:: go
foos := []Foo{foo, foo}
/* The binary representation of foos:
01020103626172FFFFFFFF0103626172FFFFFFFF
0102: `int` encoded length of array, here 2
0103626172FFFFFFFF: the first `foo`
0103626172FFFFFFFF: the second `foo`
*/
foos := [2]Foo{foo, foo} // fixed-length array
/* The binary representation of foos:
0103626172FFFFFFFF0103626172FFFFFFFF
0103626172FFFFFFFF: the first `foo`
0103626172FFFFFFFF: the second `foo`
*/
**Interfaces** can represent one of any number of concrete types. The
concrete types of an interface must first be declared with their
corresponding ``type byte``. An interface is then encoded with the
leading ``type byte``, then the binary encoding of the underlying
concrete type.
NOTE: The byte ``x00`` is reserved for the ``nil`` interface value and
``nil`` pointer values.
.. code:: go
type Animal interface{}
type Dog uint32
type Cat string
RegisterInterface(
struct{ Animal }{}, // Convenience for referencing the 'Animal' interface
ConcreteType{Dog(0), 0x01}, // Register the byte 0x01 to denote a Dog
ConcreteType{Cat(""), 0x02}, // Register the byte 0x02 to denote a Cat
)
var animal Animal = Dog(02)
/* The binary representation of animal:
010102
01: the type byte for a `Dog`
0102: the bytes of Dog(02)
*/
**Pointers** are encoded with a single leading byte ``x00`` for ``nil``
pointers, otherwise encoded with a leading byte ``x01`` followed by the
binary encoding of the value pointed to.
NOTE: It's easy to convert pointer types into interface types, since the
``type byte`` ``x00`` is always ``nil``.
JSON
----
The JSON codec is compatible with the ```binary`` <#binary>`__ codec,
and is fairly intuitive if you're already familiar with golang's JSON
encoding. Some quirks are noted below:
- variable-length and fixed-length bytes are encoded as uppercase
hexadecimal strings
- interface values are encoded as an array of two items:
``[type_byte, concrete_value]``
- times are encoded as rfc2822 strings

+ 4
- 3
glide.lock View File

@ -1,5 +1,5 @@
hash: 2c988aae9517b386ee911e4da5deb9f5034359b7e2ccf448952a3ddb9771222d
updated: 2017-06-28T13:04:20.907047164+02:00
hash: 41581813ff97225a7feb86b5accb0fe4acb3e198b64592d7452240e9473c479f
updated: 2017-08-03T19:17:16.410522485Z
imports:
- name: github.com/btcsuite/btcd
version: b8df516b4b267acf2de46be593a9d948d1d2c420
@ -61,6 +61,8 @@ imports:
version: 5ccdfb18c776b740aecaf085c4d9a2779199c279
- name: github.com/pkg/errors
version: 645ef00459ed84a119197bfb8d8205042c6df63d
- name: github.com/rcrowley/go-metrics
version: 1f30fe9094a513ce4c700b9a54458bbb0c96996c
- name: github.com/spf13/afero
version: 9be650865eab0c12963d8753212f4f9c66cdcf12
subpackages:
@ -126,7 +128,6 @@ imports:
- clist
- common
- db
- events
- flowrate
- log
- merkle


+ 11
- 9
glide.yaml View File

@ -7,11 +7,10 @@ import:
- package: github.com/golang/protobuf
subpackages:
- proto
- package: github.com/pelletier/go-toml
version: ^1.0.0
- package: github.com/gorilla/websocket
- package: github.com/pkg/errors
version: ~0.8.0
- package: github.com/rcrowley/go-metrics
- package: github.com/spf13/cobra
- package: github.com/spf13/viper
- package: github.com/tendermint/abci
@ -26,21 +25,15 @@ import:
version: ~0.6.2
subpackages:
- data
- package: github.com/tendermint/merkleeyes
version: ~0.2.4
subpackages:
- app
- iavl
- testutil
- package: github.com/tendermint/tmlibs
version: ~0.2.2
subpackages:
- autofile
- cli
- cli/flags
- clist
- common
- db
- events
- flowrate
- log
- merkle
@ -53,7 +46,16 @@ import:
subpackages:
- context
- package: google.golang.org/grpc
- package: github.com/tendermint/merkleeyes
version: ~0.2.4
subpackages:
- app
- iavl
- testutil
testImport:
- package: github.com/go-kit/kit
subpackages:
- log/term
- package: github.com/stretchr/testify
subpackages:
- assert


+ 6
- 4
mempool/mempool.go View File

@ -179,7 +179,7 @@ func (mem *Mempool) CheckTx(tx types.Tx, cb func(*abci.Response)) (err error) {
},
})
}
return nil
return nil // TODO: return an error (?)
}
mem.cache.Push(tx)
// END CACHE
@ -216,21 +216,23 @@ func (mem *Mempool) resCb(req *abci.Request, res *abci.Response) {
func (mem *Mempool) resCbNormal(req *abci.Request, res *abci.Response) {
switch r := res.Value.(type) {
case *abci.Response_CheckTx:
tx := req.GetCheckTx().Tx
if r.CheckTx.Code == abci.CodeType_OK {
mem.counter++
memTx := &mempoolTx{
counter: mem.counter,
height: int64(mem.height),
tx: req.GetCheckTx().Tx,
tx: tx,
}
mem.txs.PushBack(memTx)
mem.logger.Info("Added good transaction", "tx", tx, "res", r)
mem.notifyTxsAvailable()
} else {
// ignore bad transaction
mem.logger.Info("Bad Transaction", "res", r)
mem.logger.Info("Rejected bad transaction", "tx", tx, "res", r)
// remove from cache (it might be good later)
mem.cache.Remove(req.GetCheckTx().Tx)
mem.cache.Remove(tx)
// TODO: handle other retcodes
}


+ 8
- 10
mempool/mempool_test.go View File

@ -15,14 +15,12 @@ import (
"github.com/tendermint/tendermint/types"
)
func newMempoolWithApp(t *testing.T, cc proxy.ClientCreator) *Mempool {
func newMempoolWithApp(cc proxy.ClientCreator) *Mempool {
config := cfg.ResetTestRoot("mempool_test")
appConnMem, _ := cc.NewABCIClient()
appConnMem.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "mempool"))
if _, err := appConnMem.Start(); err != nil {
t.Fatalf("Error starting ABCI client: %v", err.Error())
}
appConnMem.Start()
mempool := NewMempool(config.Mempool, appConnMem, 0)
mempool.SetLogger(log.TestingLogger())
return mempool
@ -46,7 +44,7 @@ func ensureFire(t *testing.T, ch <-chan int, timeoutMS int) {
}
}
func sendTxs(t *testing.T, mempool *Mempool, count int) types.Txs {
func checkTxs(t *testing.T, mempool *Mempool, count int) types.Txs {
txs := make(types.Txs, count)
for i := 0; i < count; i++ {
txBytes := make([]byte, 20)
@ -63,7 +61,7 @@ func sendTxs(t *testing.T, mempool *Mempool, count int) types.Txs {
func TestTxsAvailable(t *testing.T) {
app := dummy.NewDummyApplication()
cc := proxy.NewLocalClientCreator(app)
mempool := newMempoolWithApp(t, cc)
mempool := newMempoolWithApp(cc)
mempool.EnableTxsAvailable()
timeoutMS := 500
@ -72,7 +70,7 @@ func TestTxsAvailable(t *testing.T) {
ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
// send a bunch of txs, it should only fire once
txs := sendTxs(t, mempool, 100)
txs := checkTxs(t, mempool, 100)
ensureFire(t, mempool.TxsAvailable(), timeoutMS)
ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
@ -85,7 +83,7 @@ func TestTxsAvailable(t *testing.T) {
ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
// send a bunch more txs. we already fired for this height so it shouldnt fire again
moreTxs := sendTxs(t, mempool, 50)
moreTxs := checkTxs(t, mempool, 50)
ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
// now call update with all the txs. it should not fire as there are no txs left
@ -94,7 +92,7 @@ func TestTxsAvailable(t *testing.T) {
ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
// send a bunch more txs, it should only fire once
sendTxs(t, mempool, 100)
checkTxs(t, mempool, 100)
ensureFire(t, mempool.TxsAvailable(), timeoutMS)
ensureNoFire(t, mempool.TxsAvailable(), timeoutMS)
}
@ -104,7 +102,7 @@ func TestSerialReap(t *testing.T) {
app.SetOption("serial", "on")
cc := proxy.NewLocalClientCreator(app)
mempool := newMempoolWithApp(t, cc)
mempool := newMempoolWithApp(cc)
appConnCon, _ := cc.NewABCIClient()
appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus"))
if _, err := appConnCon.Start(); err != nil {


+ 8
- 5
mempool/reactor.go View File

@ -9,6 +9,7 @@ import (
abci "github.com/tendermint/abci/types"
wire "github.com/tendermint/go-wire"
"github.com/tendermint/tmlibs/clist"
"github.com/tendermint/tmlibs/log"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
@ -40,6 +41,12 @@ func NewMempoolReactor(config *cfg.MempoolConfig, mempool *Mempool) *MempoolReac
return memR
}
// SetLogger sets the Logger on the reactor and the underlying Mempool.
func (memR *MempoolReactor) SetLogger(l log.Logger) {
memR.Logger = l
memR.Mempool.SetLogger(l)
}
// GetChannels implements Reactor.
// It returns the list of channels for this reactor.
func (memR *MempoolReactor) GetChannels() []*p2p.ChannelDescriptor {
@ -76,11 +83,7 @@ func (memR *MempoolReactor) Receive(chID byte, src *p2p.Peer, msgBytes []byte) {
case *TxMessage:
err := memR.Mempool.CheckTx(msg.Tx, nil)
if err != nil {
// Bad, seen, or conflicting tx.
memR.Logger.Info("Could not add tx", "tx", msg.Tx)
return
} else {
memR.Logger.Info("Added valid tx", "tx", msg.Tx)
memR.Logger.Info("Could not check tx", "tx", msg.Tx, "err", err)
}
// broadcasting happens from go routines per peer
default:


+ 108
- 0
mempool/reactor_test.go View File

@ -0,0 +1,108 @@
package mempool
import (
"fmt"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/go-kit/kit/log/term"
"github.com/tendermint/abci/example/dummy"
"github.com/tendermint/tmlibs/log"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
)
// mempoolLogger is a TestingLogger which uses a different
// color for each validator ("validator" key must exist).
func mempoolLogger() log.Logger {
return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor {
for i := 0; i < len(keyvals)-1; i += 2 {
if keyvals[i] == "validator" {
return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))}
}
}
return term.FgBgColor{}
})
}
// connect N mempool reactors through N switches
func makeAndConnectMempoolReactors(config *cfg.Config, N int) []*MempoolReactor {
reactors := make([]*MempoolReactor, N)
logger := mempoolLogger()
for i := 0; i < N; i++ {
app := dummy.NewDummyApplication()
cc := proxy.NewLocalClientCreator(app)
mempool := newMempoolWithApp(cc)
reactors[i] = NewMempoolReactor(config.Mempool, mempool) // so we dont start the consensus states
reactors[i].SetLogger(logger.With("validator", i))
}
p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch {
s.AddReactor("MEMPOOL", reactors[i])
return s
}, p2p.Connect2Switches)
return reactors
}
// wait for all txs on all reactors
func waitForTxs(t *testing.T, txs types.Txs, reactors []*MempoolReactor) {
// wait for the txs in all mempools
wg := new(sync.WaitGroup)
for i := 0; i < len(reactors); i++ {
wg.Add(1)
go _waitForTxs(t, wg, txs, i, reactors)
}
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
timer := time.After(TIMEOUT)
select {
case <-timer:
t.Fatal("Timed out waiting for txs")
case <-done:
}
}
// wait for all txs on a single mempool
func _waitForTxs(t *testing.T, wg *sync.WaitGroup, txs types.Txs, reactorIdx int, reactors []*MempoolReactor) {
mempool := reactors[reactorIdx].Mempool
for mempool.Size() != len(txs) {
time.Sleep(time.Second)
}
reapedTxs := mempool.Reap(len(txs))
for i, tx := range txs {
assert.Equal(t, tx, reapedTxs[i], fmt.Sprintf("txs at index %d on reactor %d don't match: %v vs %v", i, reactorIdx, tx, reapedTxs[i]))
}
wg.Done()
}
var (
NUM_TXS = 1000
TIMEOUT = 120 * time.Second // ridiculously high because CircleCI is slow
)
func TestReactorBroadcastTxMessage(t *testing.T) {
config := cfg.TestConfig()
N := 4
reactors := makeAndConnectMempoolReactors(config, N)
// send a bunch of txs to the first reactor's mempool
// and wait for them all to be received in the others
txs := checkTxs(t, reactors[0].Mempool, NUM_TXS)
waitForTxs(t, txs, reactors)
}

+ 2
- 2
node/node.go View File

@ -335,9 +335,9 @@ func (n *Node) startRPC() ([]net.Listener, error) {
listeners := make([]net.Listener, len(listenAddrs))
for i, listenAddr := range listenAddrs {
mux := http.NewServeMux()
wm := rpcserver.NewWebsocketManager(rpccore.Routes, n.evsw)
rpcLogger := n.Logger.With("module", "rpc-server")
wm.SetLogger(rpcLogger)
wm := rpcserver.NewWebsocketManager(rpccore.Routes, n.evsw)
wm.SetLogger(rpcLogger.With("protocol", "websocket"))
mux.HandleFunc("/websocket", wm.WebsocketHandler)
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, rpcLogger)
listener, err := rpcserver.StartHTTPServer(listenAddr, mux, rpcLogger)


+ 34
- 22
p2p/connection.go View File

@ -22,15 +22,15 @@ const (
updateState = 2 * time.Second
pingTimeout = 40 * time.Second
// flushThrottle used here as a default.
// overwritten by the user config.
// TODO: remove
flushThrottle = 100 * time.Millisecond
// some of these defaults are written in the user config
// flushThrottle, sendRate, recvRate
// TODO: remove values present in config
defaultFlushThrottle = 100 * time.Millisecond
defaultSendQueueCapacity = 1
defaultSendRate = int64(512000) // 500KB/s
defaultRecvBufferCapacity = 4096
defaultRecvMessageCapacity = 22020096 // 21MB
defaultSendRate = int64(512000) // 500KB/s
defaultRecvRate = int64(512000) // 500KB/s
defaultSendTimeout = 10 * time.Second
)
@ -94,15 +94,22 @@ type MConnConfig struct {
SendRate int64 `mapstructure:"send_rate"`
RecvRate int64 `mapstructure:"recv_rate"`
maxMsgPacketPayloadSize int
flushThrottle time.Duration
}
func (cfg *MConnConfig) maxMsgPacketTotalSize() int {
return cfg.maxMsgPacketPayloadSize + maxMsgPacketOverheadSize
}
// DefaultMConnConfig returns the default config.
func DefaultMConnConfig() *MConnConfig {
return &MConnConfig{
SendRate: defaultSendRate,
RecvRate: defaultRecvRate,
flushThrottle: flushThrottle,
SendRate: defaultSendRate,
RecvRate: defaultRecvRate,
maxMsgPacketPayloadSize: defaultMaxMsgPacketPayloadSize,
flushThrottle: defaultFlushThrottle,
}
}
@ -342,7 +349,7 @@ func (c *MConnection) sendSomeMsgPackets() bool {
// Block until .sendMonitor says we can write.
// Once we're ready we send more than we asked for,
// but amortized it should even out.
c.sendMonitor.Limit(maxMsgPacketTotalSize, atomic.LoadInt64(&c.config.SendRate), true)
c.sendMonitor.Limit(c.config.maxMsgPacketTotalSize(), atomic.LoadInt64(&c.config.SendRate), true)
// Now send some msgPackets.
for i := 0; i < numBatchMsgPackets; i++ {
@ -400,7 +407,7 @@ func (c *MConnection) recvRoutine() {
FOR_LOOP:
for {
// Block until .recvMonitor says we can read.
c.recvMonitor.Limit(maxMsgPacketTotalSize, atomic.LoadInt64(&c.config.RecvRate), true)
c.recvMonitor.Limit(c.config.maxMsgPacketTotalSize(), atomic.LoadInt64(&c.config.RecvRate), true)
/*
// Peek into bufReader for debugging
@ -441,7 +448,7 @@ FOR_LOOP:
c.Logger.Debug("Receive Pong")
case packetTypeMsg:
pkt, n, err := msgPacket{}, int(0), error(nil)
wire.ReadBinaryPtr(&pkt, c.bufReader, maxMsgPacketTotalSize, &n, &err)
wire.ReadBinaryPtr(&pkt, c.bufReader, c.config.maxMsgPacketTotalSize(), &n, &err)
c.recvMonitor.Update(int(n))
if err != nil {
if c.IsRunning() {
@ -464,6 +471,7 @@ FOR_LOOP:
}
if msgBytes != nil {
c.Logger.Debug("Received bytes", "chID", pkt.ChannelID, "msgBytes", msgBytes)
// NOTE: This means the reactor.Receive runs in the same thread as the p2p recv routine
c.onReceive(pkt.ChannelID, msgBytes)
}
default:
@ -547,6 +555,8 @@ type Channel struct {
sending []byte
priority int
recentlySent int64 // exponential moving average
maxMsgPacketPayloadSize int
}
func newChannel(conn *MConnection, desc *ChannelDescriptor) *Channel {
@ -555,12 +565,13 @@ func newChannel(conn *MConnection, desc *ChannelDescriptor) *Channel {
cmn.PanicSanity("Channel default priority must be a postive integer")
}
return &Channel{
conn: conn,
desc: desc,
id: desc.ID,
sendQueue: make(chan []byte, desc.SendQueueCapacity),
recving: make([]byte, 0, desc.RecvBufferCapacity),
priority: desc.Priority,
conn: conn,
desc: desc,
id: desc.ID,
sendQueue: make(chan []byte, desc.SendQueueCapacity),
recving: make([]byte, 0, desc.RecvBufferCapacity),
priority: desc.Priority,
maxMsgPacketPayloadSize: conn.config.maxMsgPacketPayloadSize,
}
}
@ -619,14 +630,15 @@ func (ch *Channel) isSendPending() bool {
func (ch *Channel) nextMsgPacket() msgPacket {
packet := msgPacket{}
packet.ChannelID = byte(ch.id)
packet.Bytes = ch.sending[:cmn.MinInt(maxMsgPacketPayloadSize, len(ch.sending))]
if len(ch.sending) <= maxMsgPacketPayloadSize {
maxSize := ch.maxMsgPacketPayloadSize
packet.Bytes = ch.sending[:cmn.MinInt(maxSize, len(ch.sending))]
if len(ch.sending) <= maxSize {
packet.EOF = byte(0x01)
ch.sending = nil
atomic.AddInt32(&ch.sendQueueSize, -1) // decrement sendQueueSize
} else {
packet.EOF = byte(0x00)
ch.sending = ch.sending[cmn.MinInt(maxMsgPacketPayloadSize, len(ch.sending)):]
ch.sending = ch.sending[cmn.MinInt(maxSize, len(ch.sending)):]
}
return packet
}
@ -675,9 +687,9 @@ func (ch *Channel) updateStats() {
//-----------------------------------------------------------------------------
const (
maxMsgPacketPayloadSize = 1024
defaultMaxMsgPacketPayloadSize = 1024
maxMsgPacketOverheadSize = 10 // It's actually lower but good enough
maxMsgPacketTotalSize = maxMsgPacketPayloadSize + maxMsgPacketOverheadSize
packetTypePing = byte(0x01)
packetTypePong = byte(0x02)
packetTypeMsg = byte(0x03)


+ 1
- 1
p2p/pex_reactor_test.go View File

@ -120,7 +120,7 @@ func TestPEXReactorReceive(t *testing.T) {
dir, err := ioutil.TempDir("", "pex_reactor")
require.Nil(err)
defer os.RemoveAll(dir)
book := NewAddrBook(dir+"addrbook.json", true)
book := NewAddrBook(dir+"addrbook.json", false)
book.SetLogger(log.TestingLogger())
r := NewPEXReactor(book)


+ 8
- 2
p2p/switch.go View File

@ -90,7 +90,13 @@ func NewSwitch(config *cfg.P2PConfig) *Switch {
dialing: cmn.NewCMap(),
nodeInfo: nil,
}
sw.peerConfig.MConfig.flushThrottle = time.Duration(config.FlushThrottleTimeout) * time.Millisecond // TODO: collapse the peerConfig into the config ?
// TODO: collapse the peerConfig into the config ?
sw.peerConfig.MConfig.flushThrottle = time.Duration(config.FlushThrottleTimeout) * time.Millisecond
sw.peerConfig.MConfig.SendRate = config.SendRate
sw.peerConfig.MConfig.RecvRate = config.RecvRate
sw.peerConfig.MConfig.maxMsgPacketPayloadSize = config.MaxMsgPacketPayloadSize
sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw)
return sw
}
@ -176,7 +182,7 @@ func (sw *Switch) OnStart() error {
return err
}
}
// Start listeners
for _, listener := range sw.listeners {
go sw.listenerRoutine(listener)


+ 0
- 41
roadmap.md View File

@ -1,41 +0,0 @@
# Tendermint Roadmap
This is an estimate of what we will be working on in Tendermint over the coming months.
It is in the same style as our [CHANGELOG](/docs/changelog)
How these changes will be rolled out in terms of versions and releases can be better [tracked on Github](https://github.com/tendermint/tendermint/issues)
Please note that Tendermint is not yet production ready;
it is pre-v1.0.0 and we make backwards incompatible changes with each minor version release.
If you require more stability in the near term, please [get in touch](/contact).
BREAKING CHANGES:
- Add more fields to the Header: NextValidatorSet, ResultsHash, EvidenceHash
- Pass evidence/voteInfo through ABCI
- Upgrade the consensus to make more real-time use of evidence during voting;
instead of +2/3 precommits for a block, a Commit becomes the entire `JSet`.
While the commit size may grow unbounded in size, it makes a fork immediately slash a +1/3 Byzantine subset of validators.
- Avoid exposing empty blocks as a first-class citizen of the blockchain
- Use a more advanced logging system
FEATURES:
- Use the chain as its own CA for nodes and validators
- Tooling to run multiple blockchains/apps, possibly in a single process
- State syncing (without transaction replay)
- Transaction indexing and improved support for querying history and state
- Add authentication and rate-limitting to the RPC
IMPROVEMENTS:
- Better Tendermint CLI
- Improve subtleties around mempool caching and logic
- Consensus optimizations:
- cache block parts for faster agreement after round changes
- Better testing of the consensus state machine (ie. use a DSL)
- Auto compiled serialization/deserialization code instead of go-wire reflection
BUG FIXES:
- Graceful handling/recovery for apps that have non-determinism or fail to halt
- Graceful handling/recovery for violations of safety, or liveness

+ 4
- 3
rpc/client/httpclient.go View File

@ -1,13 +1,14 @@
package client
import (
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
data "github.com/tendermint/go-wire/data"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/rpc/lib/client"
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
"github.com/tendermint/tendermint/types"
events "github.com/tendermint/tmlibs/events"
)
@ -349,14 +350,14 @@ func (w *WSEvents) parseEvent(data []byte) (err error) {
// no way of exposing these failures, so we panic.
// is this right? or silently ignore???
func (w *WSEvents) subscribe(event string) {
err := w.ws.Subscribe(event)
err := w.ws.Subscribe(context.TODO(), event)
if err != nil {
panic(err)
}
}
func (w *WSEvents) unsubscribe(event string) {
err := w.ws.Unsubscribe(event)
err := w.ws.Unsubscribe(context.TODO(), event)
if err != nil {
panic(err)
}


+ 15
- 0
rpc/core/README.md View File

@ -0,0 +1,15 @@
# Tendermint RPC
## Generate markdown for [Slate](https://github.com/tendermint/slate)
We are using [Slate](https://github.com/tendermint/slate) to power our RPC
documentation. If you are changing a comment, make sure to copy the resulting
changes to the slate repo and make a PR
[there](https://github.com/tendermint/slate) as well. For generating markdown
use:
```shell
go get github.com/melekes/godoc2md
godoc2md -template rpc/core/doc_template.txt github.com/tendermint/tendermint/rpc/core | grep -v -e "pipe.go" -e "routes.go" -e "dev.go" | sed 's$/src/target$https://github.com/tendermint/tendermint/tree/master/rpc/core$'
```

+ 64
- 2
rpc/core/abci.go View File

@ -6,8 +6,45 @@ import (
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
//-----------------------------------------------------------------------------
// Query the application for some information.
//
// ```shell
// curl 'localhost:46657/abci_query?path=""&data="abcd"&prove=true'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.ABCIQuery("", "abcd", true)
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "response": {
// "log": "exists",
// "height": 0,
// "proof": "010114FED0DAD959F36091AD761C922ABA3CBF1D8349990101020103011406AA2262E2F448242DF2C2607C3CDC705313EE3B0001149D16177BC71E445476174622EA559715C293740C",
// "value": "61626364",
// "key": "61626364",
// "index": -1,
// "code": 0
// }
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+--------+---------+----------+---------------------------------------|
// | path | string | false | false | Path to the data ("/a/b/c") |
// | data | []byte | false | true | Data |
// | prove | bool | false | false | Include a proof of the data inclusion |
func ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
resQuery, err := proxyAppQuery.QuerySync(abci.RequestQuery{
Path: path,
@ -23,6 +60,31 @@ func ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuer
}, nil
}
// Get some info about the application.
//
// ```shell
// curl 'localhost:46657/abci_info'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// info, err := client.ABCIInfo()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "response": {
// "data": "{\"size\":3}"
// }
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func ABCIInfo() (*ctypes.ResultABCIInfo, error) {
resInfo, err := proxyAppQuery.InfoSync()
if err != nil {


+ 221
- 7
rpc/core/blocks.go View File

@ -8,9 +8,59 @@ import (
. "github.com/tendermint/tmlibs/common"
)
//-----------------------------------------------------------------------------
// Returns at most 20 blocks
// Get block headers for minHeight <= height <= maxHeight.
//
// ```shell
// curl 'localhost:46657/blockchain?minHeight=10&maxHeight=10'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// info, err := client.BlockchainInfo(10, 10)
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "block_metas": [
// {
// "header": {
// "app_hash": "",
// "chain_id": "test-chain-6UTNIN",
// "height": 10,
// "time": "2017-05-29T15:05:53.877Z",
// "num_txs": 0,
// "last_block_id": {
// "parts": {
// "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
// "total": 1
// },
// "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
// },
// "last_commit_hash": "F31CC4282E50B3F2A58D763D233D76F26D26CABE",
// "data_hash": "",
// "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
// },
// "block_id": {
// "parts": {
// "hash": "277A4DBEF91483A18B85F2F5677ABF9694DFA40F",
// "total": 1
// },
// "hash": "96B1D2F2D201BA4BC383EB8224139DB1294944E5"
// }
// }
// ],
// "last_height": 5493
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
//
// <aside class="notice">Returns at most 20 items.</aside>
func BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResultBlockchainInfo, error) {
if maxHeight == 0 {
maxHeight = blockStore.Height()
@ -34,8 +84,105 @@ func BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResultBlockchainInfo, err
return &ctypes.ResultBlockchainInfo{blockStore.Height(), blockMetas}, nil
}
//-----------------------------------------------------------------------------
// Get block at a given height.
//
// ```shell
// curl 'localhost:46657/block?height=10'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// info, err := client.Block(10)
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "block": {
// "last_commit": {
// "precommits": [
// {
// "signature": {
// "data": "12C0D8893B8A38224488DC1DE6270DF76BB1A5E9DB1C68577706A6A97C6EC34FFD12339183D5CA8BC2F46148773823DE905B7F6F5862FD564038BB7AE03BF50D",
// "type": "ed25519"
// },
// "block_id": {
// "parts": {
// "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
// "total": 1
// },
// "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
// },
// "type": 2,
// "round": 0,
// "height": 9,
// "validator_index": 0,
// "validator_address": "E89A51D60F68385E09E716D353373B11F8FACD62"
// }
// ],
// "blockID": {
// "parts": {
// "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
// "total": 1
// },
// "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
// }
// },
// "data": {
// "txs": []
// },
// "header": {
// "app_hash": "",
// "chain_id": "test-chain-6UTNIN",
// "height": 10,
// "time": "2017-05-29T15:05:53.877Z",
// "num_txs": 0,
// "last_block_id": {
// "parts": {
// "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
// "total": 1
// },
// "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
// },
// "last_commit_hash": "F31CC4282E50B3F2A58D763D233D76F26D26CABE",
// "data_hash": "",
// "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
// }
// },
// "block_meta": {
// "header": {
// "app_hash": "",
// "chain_id": "test-chain-6UTNIN",
// "height": 10,
// "time": "2017-05-29T15:05:53.877Z",
// "num_txs": 0,
// "last_block_id": {
// "parts": {
// "hash": "3C78F00658E06744A88F24FF97A0A5011139F34A",
// "total": 1
// },
// "hash": "F70588DAB36BDA5A953D548A16F7D48C6C2DFD78"
// },
// "last_commit_hash": "F31CC4282E50B3F2A58D763D233D76F26D26CABE",
// "data_hash": "",
// "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
// },
// "block_id": {
// "parts": {
// "hash": "277A4DBEF91483A18B85F2F5677ABF9694DFA40F",
// "total": 1
// },
// "hash": "96B1D2F2D201BA4BC383EB8224139DB1294944E5"
// }
// }
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func Block(height int) (*ctypes.ResultBlock, error) {
if height == 0 {
return nil, fmt.Errorf("Height must be greater than 0")
@ -49,8 +196,75 @@ func Block(height int) (*ctypes.ResultBlock, error) {
return &ctypes.ResultBlock{blockMeta, block}, nil
}
//-----------------------------------------------------------------------------
// Get block commit at a given height.
//
// ```shell
// curl 'localhost:46657/commit?height=11'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// info, err := client.Commit(11)
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "canonical": true,
// "commit": {
// "precommits": [
// {
// "signature": {
// "data": "00970429FEC652E9E21D106A90AE8C5413759A7488775CEF4A3F44DC46C7F9D941070E4FBE9ED54DF247FA3983359A0C3A238D61DE55C75C9116D72ABC9CF50F",
// "type": "ed25519"
// },
// "block_id": {
// "parts": {
// "hash": "9E37CBF266BC044A779E09D81C456E653B89E006",
// "total": 1
// },
// "hash": "CC6E861E31CA4334E9888381B4A9137D1458AB6A"
// },
// "type": 2,
// "round": 0,
// "height": 11,
// "validator_index": 0,
// "validator_address": "E89A51D60F68385E09E716D353373B11F8FACD62"
// }
// ],
// "blockID": {
// "parts": {
// "hash": "9E37CBF266BC044A779E09D81C456E653B89E006",
// "total": 1
// },
// "hash": "CC6E861E31CA4334E9888381B4A9137D1458AB6A"
// }
// },
// "header": {
// "app_hash": "",
// "chain_id": "test-chain-6UTNIN",
// "height": 11,
// "time": "2017-05-29T15:05:54.893Z",
// "num_txs": 0,
// "last_block_id": {
// "parts": {
// "hash": "277A4DBEF91483A18B85F2F5677ABF9694DFA40F",
// "total": 1
// },
// "hash": "96B1D2F2D201BA4BC383EB8224139DB1294944E5"
// },
// "last_commit_hash": "3CE0C9727CE524BA9CB7C91E28F08E2B94001087",
// "data_hash": "",
// "validators_hash": "9365FC80F234C967BD233F5A3E2AB2F1E4B0E5AA"
// }
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func Commit(height int) (*ctypes.ResultCommit, error) {
if height == 0 {
return nil, fmt.Errorf("Height must be greater than 0")


+ 59
- 1
rpc/core/consensus.go View File

@ -1,17 +1,75 @@
package core
import (
"github.com/tendermint/go-wire"
wire "github.com/tendermint/go-wire"
cm "github.com/tendermint/tendermint/consensus"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
)
// Get current validators set along with a block height.
//
// ```shell
// curl 'localhost:46657/validators'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// state, err := client.Validators()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "validators": [
// {
// "accum": 0,
// "voting_power": 10,
// "pub_key": {
// "data": "68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D",
// "type": "ed25519"
// },
// "address": "E89A51D60F68385E09E716D353373B11F8FACD62"
// }
// ],
// "block_height": 5241
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func Validators() (*ctypes.ResultValidators, error) {
blockHeight, validators := consensusState.GetValidators()
return &ctypes.ResultValidators{blockHeight, validators}, nil
}
// Dump consensus state.
//
// ```shell
// curl 'localhost:46657/dump_consensus_state'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// state, err := client.DumpConsensusState()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "peer_round_states": [],
// "round_state": "RoundState{\n H:3537 R:0 S:RoundStepNewHeight\n StartTime: 2017-05-31 12:32:31.178653883 +0000 UTC\n CommitTime: 2017-05-31 12:32:30.178653883 +0000 UTC\n Validators: ValidatorSet{\n Proposer: Validator{E89A51D60F68385E09E716D353373B11F8FACD62 {PubKeyEd25519{68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D}} VP:10 A:0}\n Validators:\n Validator{E89A51D60F68385E09E716D353373B11F8FACD62 {PubKeyEd25519{68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D}} VP:10 A:0}\n }\n Proposal: <nil>\n ProposalBlock: nil-PartSet nil-Block\n LockedRound: 0\n LockedBlock: nil-PartSet nil-Block\n Votes: HeightVoteSet{H:3537 R:0~0\n VoteSet{H:3537 R:0 T:1 +2/3:<nil> BA{1:_} map[]}\n VoteSet{H:3537 R:0 T:2 +2/3:<nil> BA{1:_} map[]}\n }\n LastCommit: VoteSet{H:3536 R:0 T:2 +2/3:B7F988FBCDC68F9320E346EECAA76E32F6054654:1:673BE7C01F74 BA{1:X} map[]}\n LastValidators: ValidatorSet{\n Proposer: Validator{E89A51D60F68385E09E716D353373B11F8FACD62 {PubKeyEd25519{68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D}} VP:10 A:0}\n Validators:\n Validator{E89A51D60F68385E09E716D353373B11F8FACD62 {PubKeyEd25519{68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D}} VP:10 A:0}\n }\n}"
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
roundState := consensusState.GetRoundState()
peerRoundStates := []string{}


+ 107
- 0
rpc/core/doc.go View File

@ -0,0 +1,107 @@
/*
# Introduction
Tendermint supports the following RPC protocols:
* URI over HTTP
* JSONRPC over HTTP
* JSONRPC over websockets
Tendermint RPC is built using [our own RPC library](https://github.com/tendermint/tendermint/tree/master/rpc/lib). Documentation and tests for that library could be found at `tendermint/rpc/lib` directory.
## Configuration
Set the `laddr` config parameter under `[rpc]` table in the `$TMHOME/config.toml` file or the `--rpc.laddr` command-line flag to the desired protocol://host:port setting. Default: `tcp://0.0.0.0:46657`.
## Arguments
Arguments which expect strings or byte arrays may be passed as quoted strings, like `"abc"` or as `0x`-prefixed strings, like `0x616263`.
## URI/HTTP
```bash
curl 'localhost:46657/broadcast_tx_sync?tx="abc"'
```
> Response:
```json
{
"error": "",
"result": {
"hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
"log": "",
"data": "",
"code": 0
},
"id": "",
"jsonrpc": "2.0"
}
```
The first entry in the result-array (`96`) is the method this response correlates with. `96` refers to "ResultTypeBroadcastTx", see [responses.go](https://github.com/tendermint/tendermint/blob/master/rpc/core/types/responses.go) for a complete overview.
## JSONRPC/HTTP
JSONRPC requests can be POST'd to the root RPC endpoint via HTTP (e.g. `http://localhost:46657/`).
```json
{
"method": "broadcast_tx_sync",
"jsonrpc": "2.0",
"params": [ "abc" ],
"id": "dontcare"
}
```
## JSONRPC/websockets
JSONRPC requests can be made via websocket. The websocket endpoint is at `/websocket`, e.g. `localhost:46657/websocket`. Asynchronous RPC functions like event `subscribe` and `unsubscribe` are only available via websockets.
## More Examples
See the various bash tests using curl in `test/`, and examples using the `Go` API in `rpc/client/`.
## Get the list
An HTTP Get request to the root RPC endpoint shows a list of available endpoints.
```bash
curl 'localhost:46657'
```
> Response:
```plain
Available endpoints:
/abci_info
/dump_consensus_state
/genesis
/net_info
/num_unconfirmed_txs
/status
/unconfirmed_txs
/unsafe_flush_mempool
/unsafe_stop_cpu_profiler
/validators
Endpoints that require arguments:
/abci_query?path=_&data=_&prove=_
/block?height=_
/blockchain?minHeight=_&maxHeight=_
/broadcast_tx_async?tx=_
/broadcast_tx_commit?tx=_
/broadcast_tx_sync?tx=_
/commit?height=_
/dial_seeds?seeds=_
/subscribe?event=_
/tx?hash=_&prove=_
/unsafe_start_cpu_profiler?filename=_
/unsafe_write_heap_profile?filename=_
/unsubscribe?event=_
```
# Endpoints
*/
package core

+ 8
- 0
rpc/core/doc_template.txt View File

@ -0,0 +1,8 @@
{{with .PDoc}}
{{comment_md .Doc}}
{{example_html $ ""}}
{{range .Funcs}}{{$name_html := html .Name}}## [{{$name_html}}]({{posLink_url $ .Decl}})
{{comment_md .Doc}}{{end}}
{{end}}
---

+ 54
- 0
rpc/core/events.go View File

@ -6,6 +6,33 @@ import (
"github.com/tendermint/tendermint/types"
)
// Subscribe for events via WebSocket.
//
// ```go
// import "github.com/tendermint/tendermint/types"
//
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.AddListenerForEvent(types.EventStringNewBlock())
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {},
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+--------+---------+----------+-------------|
// | event | string | "" | true | Event name |
//
// <aside class="notice">WebSocket only</aside>
func Subscribe(wsCtx rpctypes.WSRPCContext, event string) (*ctypes.ResultSubscribe, error) {
logger.Info("Subscribe to event", "remote", wsCtx.GetRemoteAddr(), "event", event)
types.AddListenerForEvent(wsCtx.GetEventSwitch(), wsCtx.GetRemoteAddr(), event, func(msg types.TMEventData) {
@ -17,6 +44,33 @@ func Subscribe(wsCtx rpctypes.WSRPCContext, event string) (*ctypes.ResultSubscri
return &ctypes.ResultSubscribe{}, nil
}
// Unsubscribe from events via WebSocket.
//
// ```go
// import 'github.com/tendermint/tendermint/types'
//
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.RemoveListenerForEvent(types.EventStringNewBlock())
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {},
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+--------+---------+----------+-------------|
// | event | string | "" | true | Event name |
//
// <aside class="notice">WebSocket only</aside>
func Unsubscribe(wsCtx rpctypes.WSRPCContext, event string) (*ctypes.ResultUnsubscribe, error) {
logger.Info("Unsubscribe to event", "remote", wsCtx.GetRemoteAddr(), "event", event)
wsCtx.GetEventSwitch().RemoveListenerForEvent(event, wsCtx.GetRemoteAddr())


+ 150
- 1
rpc/core/mempool.go View File

@ -14,6 +14,37 @@ import (
// NOTE: tx should be signed, but this is only checked at the app level (not by Tendermint!)
// Returns right away, with no response
//
// ```shell
// curl 'localhost:46657/broadcast_tx_async?tx="123"'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.BroadcastTxAsync("123")
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "hash": "E39AAB7A537ABAA237831742DCE1117F187C3C52",
// "log": "",
// "data": "",
// "code": 0
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+------+---------+----------+-----------------|
// | tx | Tx | nil | true | The transaction |
func BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
err := mempool.CheckTx(tx, nil)
if err != nil {
@ -22,7 +53,38 @@ func BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return &ctypes.ResultBroadcastTx{Hash: tx.Hash()}, nil
}
// Returns with the response from CheckTx
// Returns with the response from CheckTx.
//
// ```shell
// curl 'localhost:46657/broadcast_tx_sync?tx="456"'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.BroadcastTxSync("456")
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "jsonrpc": "2.0",
// "id": "",
// "result": {
// "code": 0,
// "data": "",
// "log": "",
// "hash": "0D33F2F03A5234F38706E43004489E061AC40A2E"
// },
// "error": ""
// }
// ```
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+------+---------+----------+-----------------|
// | tx | Tx | nil | true | The transaction |
func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
resCh := make(chan *abci.Response, 1)
err := mempool.CheckTx(tx, func(res *abci.Response) {
@ -45,6 +107,45 @@ func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
// or if we timeout waiting for tx to commit.
// If CheckTx or DeliverTx fail, no error will be returned, but the returned result
// will contain a non-OK ABCI code.
//
// ```shell
// curl 'localhost:46657/broadcast_tx_commit?tx="789"'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.BroadcastTxCommit("789")
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "height": 26682,
// "hash": "75CA0F856A4DA078FC4911580360E70CEFB2EBEE",
// "deliver_tx": {
// "log": "",
// "data": "",
// "code": 0
// },
// "check_tx": {
// "log": "",
// "data": "",
// "code": 0
// }
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+------+---------+----------+-----------------|
// | tx | Tx | nil | true | The transaction |
func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
// subscribe to tx being committed in block
@ -104,11 +205,59 @@ func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
panic("Should never happen!")
}
// Get unconfirmed transactions including their number.
//
// ```shell
// curl 'localhost:46657/unconfirmed_txs'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.UnconfirmedTxs()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "txs": [],
// "n_txs": 0
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func UnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
txs := mempool.Reap(-1)
return &ctypes.ResultUnconfirmedTxs{len(txs), txs}, nil
}
// Get number of unconfirmed transactions.
//
// ```shell
// curl 'localhost:46657/num_unconfirmed_txs'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.UnconfirmedTxs()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "txs": null,
// "n_txs": 0
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
return &ctypes.ResultUnconfirmedTxs{N: mempool.Size()}, nil
}

+ 64
- 7
rpc/core/net.go View File

@ -6,8 +6,33 @@ import (
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
//-----------------------------------------------------------------------------
// Get network info.
//
// ```shell
// curl 'localhost:46657/net_info'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// info, err := client.NetInfo()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "peers": [],
// "listeners": [
// "Listener(@10.0.2.15:46656)"
// ],
// "listening": true
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func NetInfo() (*ctypes.ResultNetInfo, error) {
listening := p2pSwitch.IsListening()
listeners := []string{}
@ -29,9 +54,6 @@ func NetInfo() (*ctypes.ResultNetInfo, error) {
}, nil
}
//-----------------------------------------------------------------------------
// Dial given list of seeds
func UnsafeDialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
if len(seeds) == 0 {
@ -46,8 +68,43 @@ func UnsafeDialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
return &ctypes.ResultDialSeeds{"Dialing seeds in progress. See /net_info for details"}, nil
}
//-----------------------------------------------------------------------------
// Get genesis file.
//
// ```shell
// curl 'localhost:46657/genesis'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// genesis, err := client.Genesis()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "genesis": {
// "app_hash": "",
// "validators": [
// {
// "name": "",
// "amount": 10,
// "pub_key": {
// "data": "68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D",
// "type": "ed25519"
// }
// }
// ],
// "chain_id": "test-chain-6UTNIN",
// "genesis_time": "2017-05-29T15:05:41.671Z"
// }
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func Genesis() (*ctypes.ResultGenesis, error) {
return &ctypes.ResultGenesis{genDoc}, nil
}

+ 47
- 0
rpc/core/status.go View File

@ -6,6 +6,53 @@ import (
"github.com/tendermint/tendermint/types"
)
// Get Tendermint status including node info, pubkey, latest block
// hash, app hash, block height and time.
//
// ```shell
// curl 'localhost:46657/status'
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// result, err := client.Status()
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "latest_block_time": 1.49631773695e+18,
// "latest_block_height": 22924,
// "latest_app_hash": "9D16177BC71E445476174622EA559715C293740C",
// "latest_block_hash": "75B36EEF96C277A592D8B14867098C58F68BB180",
// "pub_key": {
// "data": "68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D",
// "type": "ed25519"
// },
// "node_info": {
// "other": [
// "wire_version=0.6.2",
// "p2p_version=0.5.0",
// "consensus_version=v1/0.2.2",
// "rpc_version=0.7.0/3",
// "tx_index=on",
// "rpc_addr=tcp://0.0.0.0:46657"
// ],
// "version": "0.10.0-rc1-aa22bd84",
// "listen_addr": "10.0.2.15:46656",
// "remote_addr": "",
// "network": "test-chain-6UTNIN",
// "moniker": "anonymous",
// "pub_key": "659B9E54DD6EF9FEF28FAD40629AF0E4BD3C2563BB037132B054A176E00F1D94"
// }
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
func Status() (*ctypes.ResultStatus, error) {
latestHeight := blockStore.Height()
var (


+ 57
- 2
rpc/core/tx.go View File

@ -8,9 +8,64 @@ import (
"github.com/tendermint/tendermint/types"
)
// Tx allow user to query the transaction results. `nil` could mean the
// transaction is in the mempool, invalidated, or was not send in the first
// Tx allows you to query the transaction results. `nil` could mean the
// transaction is in the mempool, invalidated, or was not sent in the first
// place.
//
// ```shell
// curl "localhost:46657/tx?hash=0x2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF"
// ```
//
// ```go
// client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
// tx, err := client.Tx([]byte("2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF"), true)
// ```
//
// > The above command returns JSON structured like this:
//
// ```json
// {
// "error": "",
// "result": {
// "proof": {
// "Proof": {
// "aunts": []
// },
// "Data": "YWJjZA==",
// "RootHash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF",
// "Total": 1,
// "Index": 0
// },
// "tx": "YWJjZA==",
// "tx_result": {
// "log": "",
// "data": "",
// "code": 0
// },
// "index": 0,
// "height": 52
// },
// "id": "",
// "jsonrpc": "2.0"
// }
// ```
//
// Returns a transaction matching the given transaction hash.
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+--------+---------+----------+-----------------------------------------------------------|
// | hash | []byte | nil | true | The transaction hash |
// | prove | bool | false | false | Include a proof of the transaction inclusion in the block |
//
// ### Returns
//
// - `proof`: the `types.TxProof` object
// - `tx`: `[]byte` - the transaction
// - `tx_result`: the `abci.Result` object
// - `index`: `int` - index of the transaction
// - `height`: `int` - height of the block where this transaction was in
func Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
// if index is disabled, return error


+ 1
- 1
rpc/grpc/grpc_test.go View File

@ -13,7 +13,7 @@ import (
)
func TestMain(m *testing.M) {
// start a tendermint node (and merkleeyes) in the background to test against
// start a tendermint node in the background to test against
app := dummy.NewDummyApplication()
node := rpctest.StartTendermint(app)
code := m.Run()


+ 386
- 90
rpc/lib/client/ws_client.go View File

@ -1,160 +1,456 @@
package rpcclient
import (
"context"
"encoding/json"
"fmt"
"math"
"net"
"net/http"
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
metrics "github.com/rcrowley/go-metrics"
types "github.com/tendermint/tendermint/rpc/lib/types"
cmn "github.com/tendermint/tmlibs/common"
)
const (
wsResultsChannelCapacity = 10
wsErrorsChannelCapacity = 1
wsWriteTimeoutSeconds = 10
defaultMaxReconnectAttempts = 25
defaultWriteWait = 0
defaultReadWait = 0
defaultPingPeriod = 0
)
// WSClient is a WebSocket client. The methods of WSClient are safe for use by
// multiple goroutines.
type WSClient struct {
cmn.BaseService
conn *websocket.Conn
Address string // IP:PORT or /path/to/socket
Endpoint string // /websocket/url/endpoint
Dialer func(string, string) (net.Conn, error)
*websocket.Conn
ResultsCh chan json.RawMessage // closes upon WSClient.Stop()
ErrorsCh chan error // closes upon WSClient.Stop()
// Time between sending a ping and receiving a pong. See
// https://godoc.org/github.com/rcrowley/go-metrics#Timer.
PingPongLatencyTimer metrics.Timer
// user facing channels, closed only when the client is being stopped.
ResultsCh chan json.RawMessage
ErrorsCh chan error
// internal channels
send chan types.RPCRequest // user requests
backlog chan types.RPCRequest // stores a single user request received during a conn failure
reconnectAfter chan error // reconnect requests
readRoutineQuit chan struct{} // a way for readRoutine to close writeRoutine
wg sync.WaitGroup
mtx sync.RWMutex
sentLastPingAt time.Time
reconnecting bool
// Maximum reconnect attempts (0 or greater; default: 25).
maxReconnectAttempts int
// Time allowed to write a message to the server. 0 means block until operation succeeds.
writeWait time.Duration
// Time allowed to read the next message from the server. 0 means block until operation succeeds.
readWait time.Duration
// Send pings to server with this period. Must be less than readWait. If 0, no pings will be sent.
pingPeriod time.Duration
}
// create a new connection
func NewWSClient(remoteAddr, endpoint string) *WSClient {
// NewWSClient returns a new client. See the commentary on the func(*WSClient)
// functions for a detailed description of how to configure ping period and
// pong wait time. The endpoint argument must begin with a `/`.
func NewWSClient(remoteAddr, endpoint string, options ...func(*WSClient)) *WSClient {
addr, dialer := makeHTTPDialer(remoteAddr)
wsClient := &WSClient{
Address: addr,
Dialer: dialer,
Endpoint: endpoint,
Conn: nil,
c := &WSClient{
Address: addr,
Dialer: dialer,
Endpoint: endpoint,
PingPongLatencyTimer: metrics.NewTimer(),
maxReconnectAttempts: defaultMaxReconnectAttempts,
readWait: defaultReadWait,
writeWait: defaultWriteWait,
pingPeriod: defaultPingPeriod,
}
c.BaseService = *cmn.NewBaseService(nil, "WSClient", c)
for _, option := range options {
option(c)
}
wsClient.BaseService = *cmn.NewBaseService(nil, "WSClient", wsClient)
return wsClient
return c
}
func (wsc *WSClient) String() string {
return wsc.Address + ", " + wsc.Endpoint
// MaxReconnectAttempts sets the maximum number of reconnect attempts before returning an error.
// It should only be used in the constructor and is not Goroutine-safe.
func MaxReconnectAttempts(max int) func(*WSClient) {
return func(c *WSClient) {
c.maxReconnectAttempts = max
}
}
// ReadWait sets the amount of time to wait before a websocket read times out.
// It should only be used in the constructor and is not Goroutine-safe.
func ReadWait(readWait time.Duration) func(*WSClient) {
return func(c *WSClient) {
c.readWait = readWait
}
}
// WriteWait sets the amount of time to wait before a websocket write times out.
// It should only be used in the constructor and is not Goroutine-safe.
func WriteWait(writeWait time.Duration) func(*WSClient) {
return func(c *WSClient) {
c.writeWait = writeWait
}
}
// OnStart implements cmn.BaseService interface
func (wsc *WSClient) OnStart() error {
wsc.BaseService.OnStart()
err := wsc.dial()
// PingPeriod sets the duration for sending websocket pings.
// It should only be used in the constructor - not Goroutine-safe.
func PingPeriod(pingPeriod time.Duration) func(*WSClient) {
return func(c *WSClient) {
c.pingPeriod = pingPeriod
}
}
// String returns WS client full address.
func (c *WSClient) String() string {
return fmt.Sprintf("%s (%s)", c.Address, c.Endpoint)
}
// OnStart implements cmn.Service by dialing a server and creating read and
// write routines.
func (c *WSClient) OnStart() error {
err := c.dial()
if err != nil {
return err
}
wsc.ResultsCh = make(chan json.RawMessage, wsResultsChannelCapacity)
wsc.ErrorsCh = make(chan error, wsErrorsChannelCapacity)
go wsc.receiveEventsRoutine()
c.ResultsCh = make(chan json.RawMessage)
c.ErrorsCh = make(chan error)
c.send = make(chan types.RPCRequest)
// 1 additional error may come from the read/write
// goroutine depending on which failed first.
c.reconnectAfter = make(chan error, 1)
// capacity for 1 request. a user won't be able to send more because the send
// channel is unbuffered.
c.backlog = make(chan types.RPCRequest, 1)
c.startReadWriteRoutines()
go c.reconnectRoutine()
return nil
}
// OnReset implements cmn.BaseService interface
func (wsc *WSClient) OnReset() error {
return nil
// OnStop implements cmn.Service.
func (c *WSClient) OnStop() {}
// Stop overrides cmn.Service#Stop. There is no other way to wait until Quit
// channel is closed.
func (c *WSClient) Stop() bool {
success := c.BaseService.Stop()
// only close user-facing channels when we can't write to them
c.wg.Wait()
close(c.ResultsCh)
close(c.ErrorsCh)
return success
}
// IsReconnecting returns true if the client is reconnecting right now.
func (c *WSClient) IsReconnecting() bool {
c.mtx.RLock()
defer c.mtx.RUnlock()
return c.reconnecting
}
// IsActive returns true if the client is running and not reconnecting.
func (c *WSClient) IsActive() bool {
return c.IsRunning() && !c.IsReconnecting()
}
// Send the given RPC request to the server. Results will be available on
// ResultsCh, errors, if any, on ErrorsCh. Will block until send succeeds or
// ctx.Done is closed.
func (c *WSClient) Send(ctx context.Context, request types.RPCRequest) error {
select {
case c.send <- request:
c.Logger.Info("sent a request", "req", request)
return nil
case <-ctx.Done():
return ctx.Err()
}
}
// Call the given method. See Send description.
func (c *WSClient) Call(ctx context.Context, method string, params map[string]interface{}) error {
request, err := types.MapToRequest("", method, params)
if err != nil {
return err
}
return c.Send(ctx, request)
}
// CallWithArrayParams the given method with params in a form of array. See
// Send description.
func (c *WSClient) CallWithArrayParams(ctx context.Context, method string, params []interface{}) error {
request, err := types.ArrayToRequest("", method, params)
if err != nil {
return err
}
return c.Send(ctx, request)
}
func (wsc *WSClient) dial() error {
///////////////////////////////////////////////////////////////////////////////
// Private methods
// Dial
func (c *WSClient) dial() error {
dialer := &websocket.Dialer{
NetDial: wsc.Dialer,
NetDial: c.Dialer,
Proxy: http.ProxyFromEnvironment,
}
rHeader := http.Header{}
con, _, err := dialer.Dial("ws://"+wsc.Address+wsc.Endpoint, rHeader)
conn, _, err := dialer.Dial("ws://"+c.Address+c.Endpoint, rHeader)
if err != nil {
return err
}
// Set the ping/pong handlers
con.SetPingHandler(func(m string) error {
// NOTE: https://github.com/gorilla/websocket/issues/97
go con.WriteControl(websocket.PongMessage, []byte(m), time.Now().Add(time.Second*wsWriteTimeoutSeconds))
return nil
})
con.SetPongHandler(func(m string) error {
// NOTE: https://github.com/gorilla/websocket/issues/97
return nil
})
wsc.Conn = con
c.conn = conn
return nil
}
// OnStop implements cmn.BaseService interface
func (wsc *WSClient) OnStop() {
wsc.BaseService.OnStop()
wsc.Conn.Close()
// ResultsCh/ErrorsCh is closed in receiveEventsRoutine.
}
// reconnect tries to redial up to maxReconnectAttempts with exponential
// backoff.
func (c *WSClient) reconnect() error {
attempt := 0
c.mtx.Lock()
c.reconnecting = true
c.mtx.Unlock()
defer func() {
c.mtx.Lock()
c.reconnecting = false
c.mtx.Unlock()
}()
func (wsc *WSClient) receiveEventsRoutine() {
for {
_, data, err := wsc.ReadMessage()
c.Logger.Info("reconnecting", "attempt", attempt+1)
d := time.Duration(math.Exp2(float64(attempt)))
time.Sleep(d * time.Second)
err := c.dial()
if err != nil {
wsc.Logger.Info("WSClient failed to read message", "err", err, "data", string(data))
wsc.Stop()
break
c.Logger.Error("failed to redial", "err", err)
} else {
var response types.RPCResponse
err := json.Unmarshal(data, &response)
c.Logger.Info("reconnected")
return nil
}
attempt++
if attempt > c.maxReconnectAttempts {
return errors.Wrap(err, "reached maximum reconnect attempts")
}
}
}
func (c *WSClient) startReadWriteRoutines() {
c.wg.Add(2)
c.readRoutineQuit = make(chan struct{})
go c.readRoutine()
go c.writeRoutine()
}
func (c *WSClient) processBacklog() error {
select {
case request := <-c.backlog:
if c.writeWait > 0 {
c.conn.SetWriteDeadline(time.Now().Add(c.writeWait))
}
err := c.conn.WriteJSON(request)
if err != nil {
c.Logger.Error("failed to resend request", "err", err)
c.reconnectAfter <- err
// requeue request
c.backlog <- request
return err
}
c.Logger.Info("resend a request", "req", request)
default:
}
return nil
}
func (c *WSClient) reconnectRoutine() {
for {
select {
case originalError := <-c.reconnectAfter:
// wait until writeRoutine and readRoutine finish
c.wg.Wait()
err := c.reconnect()
if err != nil {
c.Logger.Error("failed to reconnect", "err", err, "original_err", originalError)
c.Stop()
return
} else {
// drain reconnectAfter
LOOP:
for {
select {
case <-c.reconnectAfter:
default:
break LOOP
}
}
err = c.processBacklog()
if err == nil {
c.startReadWriteRoutines()
}
}
case <-c.Quit:
return
}
}
}
// The client ensures that there is at most one writer to a connection by
// executing all writes from this goroutine.
func (c *WSClient) writeRoutine() {
var ticker *time.Ticker
if c.pingPeriod > 0 {
// ticker with a predefined period
ticker = time.NewTicker(c.pingPeriod)
} else {
// ticker that never fires
ticker = &time.Ticker{C: make(<-chan time.Time)}
}
defer func() {
ticker.Stop()
c.conn.Close()
c.wg.Done()
}()
for {
select {
case request := <-c.send:
if c.writeWait > 0 {
c.conn.SetWriteDeadline(time.Now().Add(c.writeWait))
}
err := c.conn.WriteJSON(request)
if err != nil {
wsc.Logger.Info("WSClient failed to parse message", "err", err, "data", string(data))
wsc.ErrorsCh <- err
continue
c.Logger.Error("failed to send request", "err", err)
c.reconnectAfter <- err
// add request to the backlog, so we don't lose it
c.backlog <- request
return
}
if response.Error != "" {
wsc.ErrorsCh <- errors.Errorf(response.Error)
continue
case <-ticker.C:
if c.writeWait > 0 {
c.conn.SetWriteDeadline(time.Now().Add(c.writeWait))
}
wsc.ResultsCh <- *response.Result
err := c.conn.WriteMessage(websocket.PingMessage, []byte{})
if err != nil {
c.Logger.Error("failed to write ping", "err", err)
c.reconnectAfter <- err
return
}
c.mtx.Lock()
c.sentLastPingAt = time.Now()
c.mtx.Unlock()
c.Logger.Debug("sent ping")
case <-c.readRoutineQuit:
return
case <-c.Quit:
c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
return
}
}
// this must be modified in the same go-routine that reads from the
// connection to avoid race conditions
wsc.Conn = nil
}
// The client ensures that there is at most one reader to a connection by
// executing all reads from this goroutine.
func (c *WSClient) readRoutine() {
defer func() {
c.conn.Close()
c.wg.Done()
}()
c.conn.SetPongHandler(func(string) error {
// gather latency stats
c.mtx.RLock()
t := c.sentLastPingAt
c.mtx.RUnlock()
c.PingPongLatencyTimer.UpdateSince(t)
c.Logger.Debug("got pong")
return nil
})
for {
// reset deadline for every message type (control or data)
if c.readWait > 0 {
c.conn.SetReadDeadline(time.Now().Add(c.readWait))
}
_, data, err := c.conn.ReadMessage()
if err != nil {
if !websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
return
}
c.Logger.Error("failed to read response", "err", err)
close(c.readRoutineQuit)
c.reconnectAfter <- err
return
}
// Cleanup
close(wsc.ResultsCh)
close(wsc.ErrorsCh)
var response types.RPCResponse
err = json.Unmarshal(data, &response)
if err != nil {
c.Logger.Error("failed to parse response", "err", err, "data", string(data))
c.ErrorsCh <- err
continue
}
if response.Error != "" {
c.ErrorsCh <- errors.Errorf(response.Error)
continue
}
c.Logger.Info("got response", "resp", response.Result)
c.ResultsCh <- *response.Result
}
}
///////////////////////////////////////////////////////////////////////////////
// Predefined methods
// Subscribe to an event. Note the server must have a "subscribe" route
// defined.
func (wsc *WSClient) Subscribe(eventid string) error {
params := map[string]interface{}{"event": eventid}
request, err := types.MapToRequest("", "subscribe", params)
if err == nil {
err = wsc.WriteJSON(request)
}
return err
func (c *WSClient) Subscribe(ctx context.Context, eventType string) error {
params := map[string]interface{}{"event": eventType}
return c.Call(ctx, "subscribe", params)
}
// Unsubscribe from an event. Note the server must have a "unsubscribe" route
// defined.
func (wsc *WSClient) Unsubscribe(eventid string) error {
params := map[string]interface{}{"event": eventid}
request, err := types.MapToRequest("", "unsubscribe", params)
if err == nil {
err = wsc.WriteJSON(request)
}
return err
func (c *WSClient) Unsubscribe(ctx context.Context, eventType string) error {
params := map[string]interface{}{"event": eventType}
return c.Call(ctx, "unsubscribe", params)
}
// Call asynchronously calls a given method by sending an RPCRequest to the
// server. Results will be available on ResultsCh, errors, if any, on ErrorsCh.
func (wsc *WSClient) Call(method string, params map[string]interface{}) error {
request, err := types.MapToRequest("", method, params)
if err == nil {
err = wsc.WriteJSON(request)
}
return err
// UnsubscribeAll from all. Note the server must have a "unsubscribe_all" route
// defined.
func (c *WSClient) UnsubscribeAll(ctx context.Context) error {
params := map[string]interface{}{}
return c.Call(ctx, "unsubscribe_all", params)
}

+ 193
- 0
rpc/lib/client/ws_client_test.go View File

@ -0,0 +1,193 @@
package rpcclient
import (
"context"
"encoding/json"
"net"
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/require"
"github.com/tendermint/tmlibs/log"
types "github.com/tendermint/tendermint/rpc/lib/types"
)
type myHandler struct {
closeConnAfterRead bool
mtx sync.RWMutex
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
panic(err)
}
defer conn.Close()
for {
messageType, _, err := conn.ReadMessage()
if err != nil {
return
}
h.mtx.RLock()
if h.closeConnAfterRead {
conn.Close()
}
h.mtx.RUnlock()
res := json.RawMessage(`{}`)
emptyRespBytes, _ := json.Marshal(types.RPCResponse{Result: &res})
if err := conn.WriteMessage(messageType, emptyRespBytes); err != nil {
return
}
}
}
func TestWSClientReconnectsAfterReadFailure(t *testing.T) {
var wg sync.WaitGroup
// start server
h := &myHandler{}
s := httptest.NewServer(h)
defer s.Close()
c := startClient(t, s.Listener.Addr())
defer c.Stop()
wg.Add(1)
go callWgDoneOnResult(t, c, &wg)
h.mtx.Lock()
h.closeConnAfterRead = true
h.mtx.Unlock()
// results in WS read error, no send retry because write succeeded
call(t, "a", c)
// expect to reconnect almost immediately
time.Sleep(10 * time.Millisecond)
h.mtx.Lock()
h.closeConnAfterRead = false
h.mtx.Unlock()
// should succeed
call(t, "b", c)
wg.Wait()
}
func TestWSClientReconnectsAfterWriteFailure(t *testing.T) {
var wg sync.WaitGroup
// start server
h := &myHandler{}
s := httptest.NewServer(h)
c := startClient(t, s.Listener.Addr())
defer c.Stop()
wg.Add(2)
go callWgDoneOnResult(t, c, &wg)
// hacky way to abort the connection before write
c.conn.Close()
// results in WS write error, the client should resend on reconnect
call(t, "a", c)
// expect to reconnect almost immediately
time.Sleep(10 * time.Millisecond)
// should succeed
call(t, "b", c)
wg.Wait()
}
func TestWSClientReconnectFailure(t *testing.T) {
// start server
h := &myHandler{}
s := httptest.NewServer(h)
c := startClient(t, s.Listener.Addr())
defer c.Stop()
go func() {
for {
select {
case <-c.ResultsCh:
case <-c.ErrorsCh:
case <-c.Quit:
return
}
}
}()
// hacky way to abort the connection before write
c.conn.Close()
s.Close()
// results in WS write error
// provide timeout to avoid blocking
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
c.Call(ctx, "a", make(map[string]interface{}))
// expect to reconnect almost immediately
time.Sleep(10 * time.Millisecond)
done := make(chan struct{})
go func() {
// client should block on this
call(t, "b", c)
close(done)
}()
// test that client blocks on the second send
select {
case <-done:
t.Fatal("client should block on calling 'b' during reconnect")
case <-time.After(5 * time.Second):
t.Log("All good")
}
}
func startClient(t *testing.T, addr net.Addr) *WSClient {
c := NewWSClient(addr.String(), "/websocket")
_, err := c.Start()
require.Nil(t, err)
c.SetLogger(log.TestingLogger())
return c
}
func call(t *testing.T, method string, c *WSClient) {
err := c.Call(context.Background(), method, make(map[string]interface{}))
require.NoError(t, err)
}
func callWgDoneOnResult(t *testing.T, c *WSClient, wg *sync.WaitGroup) {
for {
select {
case res := <-c.ResultsCh:
if res != nil {
wg.Done()
}
case err := <-c.ErrorsCh:
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
case <-c.Quit:
return
}
}
}

+ 53
- 14
rpc/lib/rpc_test.go View File

@ -2,15 +2,18 @@ package rpc
import (
"bytes"
"context"
crand "crypto/rand"
"encoding/json"
"fmt"
"math/rand"
"net/http"
"os"
"os/exec"
"testing"
"time"
"github.com/go-kit/kit/log/term"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/go-wire/data"
@ -75,8 +78,29 @@ func EchoDataBytesResult(v data.Bytes) (*ResultEchoDataBytes, error) {
return &ResultEchoDataBytes{v}, nil
}
func TestMain(m *testing.M) {
setup()
code := m.Run()
os.Exit(code)
}
var colorFn = func(keyvals ...interface{}) term.FgBgColor {
for i := 0; i < len(keyvals)-1; i += 2 {
if keyvals[i] == "socket" {
if keyvals[i+1] == "tcp" {
return term.FgBgColor{Fg: term.DarkBlue}
} else if keyvals[i+1] == "unix" {
return term.FgBgColor{Fg: term.DarkCyan}
}
}
}
return term.FgBgColor{}
}
// launch unix and tcp servers
func init() {
func setup() {
logger := log.NewTMLoggerWithColorFn(log.NewSyncWriter(os.Stdout), colorFn)
cmd := exec.Command("rm", "-f", unixSocket)
err := cmd.Start()
if err != nil {
@ -86,25 +110,27 @@ func init() {
panic(err)
}
tcpLogger := logger.With("socket", "tcp")
mux := http.NewServeMux()
server.RegisterRPCFuncs(mux, Routes, log.TestingLogger())
wm := server.NewWebsocketManager(Routes, nil)
wm.SetLogger(log.TestingLogger())
server.RegisterRPCFuncs(mux, Routes, tcpLogger)
wm := server.NewWebsocketManager(Routes, nil, server.ReadWait(5*time.Second), server.PingPeriod(1*time.Second))
wm.SetLogger(tcpLogger)
mux.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
go func() {
_, err := server.StartHTTPServer(tcpAddr, mux, log.TestingLogger())
_, err := server.StartHTTPServer(tcpAddr, mux, tcpLogger)
if err != nil {
panic(err)
}
}()
unixLogger := logger.With("socket", "unix")
mux2 := http.NewServeMux()
server.RegisterRPCFuncs(mux2, Routes, log.TestingLogger())
server.RegisterRPCFuncs(mux2, Routes, unixLogger)
wm = server.NewWebsocketManager(Routes, nil)
wm.SetLogger(log.TestingLogger())
wm.SetLogger(unixLogger)
mux2.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
go func() {
_, err := server.StartHTTPServer(unixAddr, mux2, log.TestingLogger())
_, err := server.StartHTTPServer(unixAddr, mux2, unixLogger)
if err != nil {
panic(err)
}
@ -184,7 +210,7 @@ func echoViaWS(cl *client.WSClient, val string) (string, error) {
params := map[string]interface{}{
"arg": val,
}
err := cl.Call("echo", params)
err := cl.Call(context.Background(), "echo", params)
if err != nil {
return "", err
}
@ -206,7 +232,7 @@ func echoBytesViaWS(cl *client.WSClient, bytes []byte) ([]byte, error) {
params := map[string]interface{}{
"arg": bytes,
}
err := cl.Call("echo_bytes", params)
err := cl.Call(context.Background(), "echo_bytes", params)
if err != nil {
return []byte{}, err
}
@ -250,6 +276,7 @@ func TestServersAndClientsBasic(t *testing.T) {
testWithHTTPClient(t, cl2)
cl3 := client.NewWSClient(addr, websocketEndpoint)
cl3.SetLogger(log.TestingLogger())
_, err := cl3.Start()
require.Nil(t, err)
fmt.Printf("=== testing server on %s using %v client", addr, cl3)
@ -278,6 +305,7 @@ func TestQuotedStringArg(t *testing.T) {
func TestWSNewWSRPCFunc(t *testing.T) {
cl := client.NewWSClient(tcpAddr, websocketEndpoint)
cl.SetLogger(log.TestingLogger())
_, err := cl.Start()
require.Nil(t, err)
defer cl.Stop()
@ -286,7 +314,7 @@ func TestWSNewWSRPCFunc(t *testing.T) {
params := map[string]interface{}{
"arg": val,
}
err = cl.Call("echo_ws", params)
err = cl.Call(context.Background(), "echo_ws", params)
require.Nil(t, err)
select {
@ -303,15 +331,14 @@ func TestWSNewWSRPCFunc(t *testing.T) {
func TestWSHandlesArrayParams(t *testing.T) {
cl := client.NewWSClient(tcpAddr, websocketEndpoint)
cl.SetLogger(log.TestingLogger())
_, err := cl.Start()
require.Nil(t, err)
defer cl.Stop()
val := "acbd"
params := []interface{}{val}
request, err := types.ArrayToRequest("", "echo_ws", params)
require.Nil(t, err)
err = cl.WriteJSON(request)
err = cl.CallWithArrayParams(context.Background(), "echo_ws", params)
require.Nil(t, err)
select {
@ -326,6 +353,18 @@ func TestWSHandlesArrayParams(t *testing.T) {
}
}
// TestWSClientPingPong checks that a client & server exchange pings
// & pongs so connection stays alive.
func TestWSClientPingPong(t *testing.T) {
cl := client.NewWSClient(tcpAddr, websocketEndpoint)
cl.SetLogger(log.TestingLogger())
_, err := cl.Start()
require.Nil(t, err)
defer cl.Stop()
time.Sleep(3 * time.Second)
}
func randBytes(t *testing.T) []byte {
n := rand.Intn(10) + 2
buf := make([]byte, n)


+ 140
- 94
rpc/lib/server/handlers.go View File

@ -21,7 +21,7 @@ import (
"github.com/tendermint/tmlibs/log"
)
// Adds a route for each function in the funcMap, as well as general jsonrpc and websocket handlers for all functions.
// RegisterRPCFuncs adds a route for each function in the funcMap, as well as general jsonrpc and websocket handlers for all functions.
// "result" is the interface on which the result objects are registered, and is popualted with every RPCResponse
func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc, logger log.Logger) {
// HTTP endpoints
@ -36,7 +36,7 @@ func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc, logger lo
//-------------------------------------
// function introspection
// holds all type information for each function
// RPCFunc contains the introspected type information for a function
type RPCFunc struct {
f reflect.Value // underlying rpc function
args []reflect.Type // type of each function arg
@ -45,12 +45,13 @@ type RPCFunc struct {
ws bool // websocket only
}
// wraps a function for quicker introspection
// NewRPCFunc wraps a function for introspection.
// f is the function, args are comma separated argument names
func NewRPCFunc(f interface{}, args string) *RPCFunc {
return newRPCFunc(f, args, false)
}
// NewWSRPCFunc wraps a function for introspection and use in the websockets.
func NewWSRPCFunc(f interface{}, args string) *RPCFunc {
return newRPCFunc(f, args, true)
}
@ -337,10 +338,10 @@ func nonJsonToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) {
// rpc.websocket
const (
writeChanCapacity = 1000
wsWriteTimeoutSeconds = 30 // each write times out after this.
wsReadTimeoutSeconds = 30 // connection times out if we haven't received *anything* in this long, not even pings.
wsPingTickerSeconds = 10 // send a ping every PingTickerSeconds.
defaultWSWriteChanCapacity = 1000
defaultWSWriteWait = 10 * time.Second
defaultWSReadWait = 30 * time.Second
defaultWSPingPeriod = (defaultWSReadWait * 9) / 10
)
// a single websocket connection
@ -349,95 +350,116 @@ const (
type wsConnection struct {
cmn.BaseService
remoteAddr string
baseConn *websocket.Conn
writeChan chan types.RPCResponse
readTimeout *time.Timer
pingTicker *time.Ticker
remoteAddr string
baseConn *websocket.Conn
writeChan chan types.RPCResponse
funcMap map[string]*RPCFunc
evsw events.EventSwitch
// write channel capacity
writeChanCapacity int
// each write times out after this.
writeWait time.Duration
// Connection times out if we haven't received *anything* in this long, not even pings.
readWait time.Duration
// Send pings to server with this period. Must be less than readWait, but greater than zero.
pingPeriod time.Duration
}
// new websocket connection wrapper
func NewWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, evsw events.EventSwitch) *wsConnection {
// NewWSConnection wraps websocket.Conn. See the commentary on the
// func(*wsConnection) functions for a detailed description of how to configure
// ping period and pong wait time.
// NOTE: if the write buffer is full, pongs may be dropped, which may cause clients to disconnect.
// see https://github.com/gorilla/websocket/issues/97
func NewWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, evsw events.EventSwitch, options ...func(*wsConnection)) *wsConnection {
wsc := &wsConnection{
remoteAddr: baseConn.RemoteAddr().String(),
baseConn: baseConn,
writeChan: make(chan types.RPCResponse, writeChanCapacity), // error when full.
funcMap: funcMap,
evsw: evsw,
remoteAddr: baseConn.RemoteAddr().String(),
baseConn: baseConn,
funcMap: funcMap,
evsw: evsw,
writeWait: defaultWSWriteWait,
writeChanCapacity: defaultWSWriteChanCapacity,
readWait: defaultWSReadWait,
pingPeriod: defaultWSPingPeriod,
}
for _, option := range options {
option(wsc)
}
wsc.BaseService = *cmn.NewBaseService(nil, "wsConnection", wsc)
return wsc
}
// wsc.Start() blocks until the connection closes.
func (wsc *wsConnection) OnStart() error {
wsc.BaseService.OnStart()
// WriteWait sets the amount of time to wait before a websocket write times out.
// It should only be used in the constructor - not Goroutine-safe.
func WriteWait(writeWait time.Duration) func(*wsConnection) {
return func(wsc *wsConnection) {
wsc.writeWait = writeWait
}
}
// these must be set before the readRoutine is created, as it may
// call wsc.Stop(), which accesses these timers
wsc.readTimeout = time.NewTimer(time.Second * wsReadTimeoutSeconds)
wsc.pingTicker = time.NewTicker(time.Second * wsPingTickerSeconds)
// WriteChanCapacity sets the capacity of the websocket write channel.
// It should only be used in the constructor - not Goroutine-safe.
func WriteChanCapacity(cap int) func(*wsConnection) {
return func(wsc *wsConnection) {
wsc.writeChanCapacity = cap
}
}
// Read subscriptions/unsubscriptions to events
go wsc.readRoutine()
// ReadWait sets the amount of time to wait before a websocket read times out.
// It should only be used in the constructor - not Goroutine-safe.
func ReadWait(readWait time.Duration) func(*wsConnection) {
return func(wsc *wsConnection) {
wsc.readWait = readWait
}
}
// Custom Ping handler to touch readTimeout
wsc.baseConn.SetPingHandler(func(m string) error {
// NOTE: https://github.com/gorilla/websocket/issues/97
go wsc.baseConn.WriteControl(websocket.PongMessage, []byte(m), time.Now().Add(time.Second*wsWriteTimeoutSeconds))
wsc.readTimeout.Reset(time.Second * wsReadTimeoutSeconds)
return nil
})
wsc.baseConn.SetPongHandler(func(m string) error {
// NOTE: https://github.com/gorilla/websocket/issues/97
wsc.readTimeout.Reset(time.Second * wsReadTimeoutSeconds)
return nil
})
go wsc.readTimeoutRoutine()
// PingPeriod sets the duration for sending websocket pings.
// It should only be used in the constructor - not Goroutine-safe.
func PingPeriod(pingPeriod time.Duration) func(*wsConnection) {
return func(wsc *wsConnection) {
wsc.pingPeriod = pingPeriod
}
}
// OnStart starts the read and write routines. It blocks until the connection closes.
func (wsc *wsConnection) OnStart() error {
wsc.writeChan = make(chan types.RPCResponse, wsc.writeChanCapacity)
// Read subscriptions/unsubscriptions to events
go wsc.readRoutine()
// Write responses, BLOCKING.
wsc.writeRoutine()
return nil
}
// OnStop unsubscribes from all events.
func (wsc *wsConnection) OnStop() {
wsc.BaseService.OnStop()
if wsc.evsw != nil {
wsc.evsw.RemoveListener(wsc.remoteAddr)
}
wsc.readTimeout.Stop()
wsc.pingTicker.Stop()
// The write loop closes the websocket connection
// when it exits its loop, and the read loop
// closes the writeChan
}
func (wsc *wsConnection) readTimeoutRoutine() {
select {
case <-wsc.readTimeout.C:
wsc.Logger.Info("Stopping connection due to read timeout")
wsc.Stop()
case <-wsc.Quit:
return
}
// Both read and write loops close the websocket connection when they exit their loops.
// The writeChan is never closed, to allow WriteRPCResponse() to fail.
}
// Implements WSRPCConnection
// GetRemoteAddr returns the remote address of the underlying connection.
// It implements WSRPCConnection
func (wsc *wsConnection) GetRemoteAddr() string {
return wsc.remoteAddr
}
// Implements WSRPCConnection
// GetEventSwitch returns the event switch.
// It implements WSRPCConnection
func (wsc *wsConnection) GetEventSwitch() events.EventSwitch {
return wsc.evsw
}
// Implements WSRPCConnection
// Blocking write to writeChan until service stops.
// Goroutine-safe
// WriteRPCResponse pushes a response to the writeChan, and blocks until it is accepted.
// It implements WSRPCConnection. It is Goroutine-safe.
func (wsc *wsConnection) WriteRPCResponse(resp types.RPCResponse) {
select {
case <-wsc.Quit:
@ -446,9 +468,8 @@ func (wsc *wsConnection) WriteRPCResponse(resp types.RPCResponse) {
}
}
// Implements WSRPCConnection
// Nonblocking write.
// Goroutine-safe
// TryWriteRPCResponse attempts to push a response to the writeChan, but does not block.
// It implements WSRPCConnection. It is Goroutine-safe
func (wsc *wsConnection) TryWriteRPCResponse(resp types.RPCResponse) bool {
select {
case <-wsc.Quit:
@ -462,27 +483,29 @@ func (wsc *wsConnection) TryWriteRPCResponse(resp types.RPCResponse) bool {
// Read from the socket and subscribe to or unsubscribe from events
func (wsc *wsConnection) readRoutine() {
// Do not close writeChan, to allow WriteRPCResponse() to fail.
// defer close(wsc.writeChan)
defer func() {
wsc.baseConn.Close()
}()
for {
select {
case <-wsc.Quit:
return
default:
// reset deadline for every type of message (control or data)
wsc.baseConn.SetReadDeadline(time.Now().Add(wsc.readWait))
var in []byte
// Do not set a deadline here like below:
// wsc.baseConn.SetReadDeadline(time.Now().Add(time.Second * wsReadTimeoutSeconds))
// The client may not send anything for a while.
// We use `readTimeout` to handle read timeouts.
_, in, err := wsc.baseConn.ReadMessage()
if err != nil {
wsc.Logger.Info("Failed to read from connection", "remote", wsc.remoteAddr, "err", err.Error())
// an error reading the connection,
// kill the connection
if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
wsc.Logger.Info("Client closed the connection")
} else {
wsc.Logger.Error("Failed to read request", "err", err)
}
wsc.Stop()
return
}
var request types.RPCRequest
err = json.Unmarshal(in, &request)
if err != nil {
@ -529,15 +552,33 @@ func (wsc *wsConnection) readRoutine() {
// receives on a write channel and writes out on the socket
func (wsc *wsConnection) writeRoutine() {
defer wsc.baseConn.Close()
pingTicker := time.NewTicker(wsc.pingPeriod)
defer func() {
pingTicker.Stop()
wsc.baseConn.Close()
}()
// https://github.com/gorilla/websocket/issues/97
pongs := make(chan string, 1)
wsc.baseConn.SetPingHandler(func(m string) error {
select {
case pongs <- m:
default:
}
return nil
})
for {
select {
case <-wsc.Quit:
return
case <-wsc.pingTicker.C:
case m := <-pongs:
err := wsc.writeMessageWithDeadline(websocket.PongMessage, []byte(m))
if err != nil {
wsc.Logger.Info("Failed to write pong (client may disconnect)", "err", err)
}
case <-pingTicker.C:
err := wsc.writeMessageWithDeadline(websocket.PingMessage, []byte{})
if err != nil {
wsc.Logger.Error("Failed to write ping message on websocket", "err", err)
wsc.Logger.Error("Failed to write ping", "err", err)
wsc.Stop()
return
}
@ -547,11 +588,13 @@ func (wsc *wsConnection) writeRoutine() {
wsc.Logger.Error("Failed to marshal RPCResponse to JSON", "err", err)
} else {
if err = wsc.writeMessageWithDeadline(websocket.TextMessage, jsonBytes); err != nil {
wsc.Logger.Error("Failed to write response on websocket", "err", err)
wsc.Logger.Error("Failed to write response", "err", err)
wsc.Stop()
return
}
}
case <-wsc.Quit:
return
}
}
}
@ -559,43 +602,46 @@ func (wsc *wsConnection) writeRoutine() {
// All writes to the websocket must (re)set the write deadline.
// If some writes don't set it while others do, they may timeout incorrectly (https://github.com/tendermint/tendermint/issues/553)
func (wsc *wsConnection) writeMessageWithDeadline(msgType int, msg []byte) error {
wsc.baseConn.SetWriteDeadline(time.Now().Add(time.Second * wsWriteTimeoutSeconds))
wsc.baseConn.SetWriteDeadline(time.Now().Add(wsc.writeWait))
return wsc.baseConn.WriteMessage(msgType, msg)
}
//----------------------------------------
// Main manager for all websocket connections
// Holds the event switch
// WebsocketManager is the main manager for all websocket connections.
// It holds the event switch and a map of functions for routing.
// NOTE: The websocket path is defined externally, e.g. in node/node.go
type WebsocketManager struct {
websocket.Upgrader
funcMap map[string]*RPCFunc
evsw events.EventSwitch
logger log.Logger
funcMap map[string]*RPCFunc
evsw events.EventSwitch
logger log.Logger
wsConnOptions []func(*wsConnection)
}
func NewWebsocketManager(funcMap map[string]*RPCFunc, evsw events.EventSwitch) *WebsocketManager {
// NewWebsocketManager returns a new WebsocketManager that routes according to the given funcMap, listens on the given event switch,
// and connects to the server with the given connection options.
func NewWebsocketManager(funcMap map[string]*RPCFunc, evsw events.EventSwitch, wsConnOptions ...func(*wsConnection)) *WebsocketManager {
return &WebsocketManager{
funcMap: funcMap,
evsw: evsw,
Upgrader: websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
// TODO
// TODO ???
return true
},
},
logger: log.NewNopLogger(),
logger: log.NewNopLogger(),
wsConnOptions: wsConnOptions,
}
}
// SetLogger sets the logger.
func (wm *WebsocketManager) SetLogger(l log.Logger) {
wm.logger = l
}
// Upgrade the request/response (via http.Hijack) and starts the wsConnection.
// WebsocketHandler upgrades the request/response (via http.Hijack) and starts the wsConnection.
func (wm *WebsocketManager) WebsocketHandler(w http.ResponseWriter, r *http.Request) {
wsConn, err := wm.Upgrade(w, r, nil)
if err != nil {
@ -605,8 +651,8 @@ func (wm *WebsocketManager) WebsocketHandler(w http.ResponseWriter, r *http.Requ
}
// register connection
con := NewWSConnection(wsConn, wm.funcMap, wm.evsw)
con.SetLogger(wm.logger)
con := NewWSConnection(wsConn, wm.funcMap, wm.evsw, wm.wsConnOptions...)
con.SetLogger(wm.logger.With("remote", wsConn.RemoteAddr()))
wm.logger.Info("New websocket connection", "remote", con.remoteAddr)
con.Start() // Blocking
}


+ 13
- 0
rpc/lib/types/types.go View File

@ -2,6 +2,7 @@ package rpctypes
import (
"encoding/json"
"fmt"
"strings"
events "github.com/tendermint/tmlibs/events"
@ -23,6 +24,10 @@ func NewRPCRequest(id string, method string, params json.RawMessage) RPCRequest
}
}
func (req RPCRequest) String() string {
return fmt.Sprintf("[%s %s]", req.ID, req.Method)
}
func MapToRequest(id string, method string, params map[string]interface{}) (RPCRequest, error) {
payload, err := json.Marshal(params)
if err != nil {
@ -70,6 +75,14 @@ func NewRPCResponse(id string, res interface{}, err string) RPCResponse {
}
}
func (resp RPCResponse) String() string {
if resp.Error == "" {
return fmt.Sprintf("[%s %v]", resp.ID, resp.Result)
} else {
return fmt.Sprintf("[%s %s]", resp.ID, resp.Error)
}
}
//----------------------------------------
// *wsConnection implements this interface.


+ 9
- 6
state/execution.go View File

@ -170,6 +170,7 @@ func commitBitArrayFromBlock(block *types.Block) *cmn.BitArray {
//-----------------------------------------------------
// Validate block
// ValidateBlock validates the block against the state.
func (s *State) ValidateBlock(block *types.Block) error {
return s.validateBlock(block)
}
@ -206,7 +207,9 @@ func (s *State) validateBlock(block *types.Block) error {
// then commits and updates the mempool atomically, then saves state.
// Transaction results are optionally indexed.
// Validate, execute, and commit block against app, save block and state
// ApplyBlock validates the block against the state, executes it against the app,
// commits it, and saves the block and state. It's the only function that needs to be called
// from outside this package to process and commit an entire block.
func (s *State) ApplyBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnConsensus,
block *types.Block, partsHeader types.PartSetHeader, mempool types.Mempool) error {
@ -242,9 +245,9 @@ func (s *State) ApplyBlock(eventCache types.Fireable, proxyAppConn proxy.AppConn
return nil
}
// mempool must be locked during commit and update
// because state is typically reset on Commit and old txs must be replayed
// against committed state before new txs are run in the mempool, lest they be invalid
// CommitStateUpdateMempool locks the mempool, runs the ABCI Commit message, and updates the mempool.
// The Mempool must be locked during commit and update because state is typically reset on Commit and old txs must be replayed
// against committed state before new txs are run in the mempool, lest they be invalid.
func (s *State) CommitStateUpdateMempool(proxyAppConn proxy.AppConnConsensus, block *types.Block, mempool types.Mempool) error {
mempool.Lock()
defer mempool.Unlock()
@ -286,8 +289,8 @@ func (s *State) indexTxs(abciResponses *ABCIResponses) {
s.TxIndexer.AddBatch(batch)
}
// Exec and commit a block on the proxyApp without validating or mutating the state
// Returns the application root hash (result of abci.Commit)
// ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
// It returns the application root hash (result of abci.Commit).
func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block, logger log.Logger) ([]byte, error) {
var eventCache types.Fireable // nil
_, err := execBlockOnProxyApp(eventCache, appConnConsensus, block, logger)


+ 24
- 22
state/state.go View File

@ -24,6 +24,9 @@ var (
//-----------------------------------------------------------------------------
// State represents the latest committed state of the Tendermint consensus,
// including the last committed block and validator set.
// Newly committed blocks are validated and executed against the State.
// NOTE: not goroutine-safe.
type State struct {
// mtx for writing to db
@ -49,6 +52,7 @@ type State struct {
logger log.Logger
}
// LoadState loads the State from the database.
func LoadState(db dbm.DB) *State {
return loadState(db, stateKey)
}
@ -70,10 +74,12 @@ func loadState(db dbm.DB, key []byte) *State {
return s
}
// SetLogger sets the logger on the State.
func (s *State) SetLogger(l log.Logger) {
s.logger = l
}
// Copy makes a copy of the State for mutating.
func (s *State) Copy() *State {
return &State{
db: s.db,
@ -90,19 +96,20 @@ func (s *State) Copy() *State {
}
}
// Save persists the State to the database.
func (s *State) Save() {
s.mtx.Lock()
defer s.mtx.Unlock()
s.db.SetSync(stateKey, s.Bytes())
}
// Sets the ABCIResponses in the state and writes them to disk
// in case we crash after app.Commit and before s.Save()
// SaveABCIResponses persists the ABCIResponses to the database.
// This is useful in case we crash after app.Commit and before s.Save().
func (s *State) SaveABCIResponses(abciResponses *ABCIResponses) {
// save the validators to the db
s.db.SetSync(abciResponsesKey, abciResponses.Bytes())
}
// LoadABCIResponses loads the ABCIResponses from the database.
func (s *State) LoadABCIResponses() *ABCIResponses {
abciResponses := new(ABCIResponses)
@ -119,21 +126,17 @@ func (s *State) LoadABCIResponses() *ABCIResponses {
return abciResponses
}
// Equals returns true if the States are identical.
func (s *State) Equals(s2 *State) bool {
return bytes.Equal(s.Bytes(), s2.Bytes())
}
// Bytes serializes the State using go-wire.
func (s *State) Bytes() []byte {
buf, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(s, buf, n, err)
if *err != nil {
cmn.PanicCrisis(*err)
}
return buf.Bytes()
return wire.BinaryBytes(s)
}
// Mutate state variables to match block and validators
// after running EndBlock
// SetBlockAndValidators mutates State variables to update block and validators after running EndBlock.
func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader, abciResponses *ABCIResponses) {
// copy the valset so we can apply changes from EndBlock
@ -141,7 +144,6 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ
prevValSet := s.Validators.Copy()
nextValSet := prevValSet.Copy()
// update the validator set with the latest abciResponses
err := updateValidators(nextValSet, abciResponses.EndBlock.Diffs)
if err != nil {
s.logger.Error("Error changing validator set", "err", err)
@ -154,6 +156,7 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ
s.setBlockAndValidators(header.Height,
types.BlockID{header.Hash(), blockPartsHeader}, header.Time,
prevValSet, nextValSet)
}
func (s *State) setBlockAndValidators(
@ -167,12 +170,14 @@ func (s *State) setBlockAndValidators(
s.LastValidators = prevValSet
}
// GetValidators returns the last and current validator sets.
func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) {
return s.LastValidators, s.Validators
}
// Load the most recent state from "state" db,
// or create a new one (and save) from genesis.
// GetState loads the most recent state from the database,
// or creates a new one from the given genesisFile and persists the result
// to the database.
func GetState(stateDB dbm.DB, genesisFile string) *State {
state := LoadState(stateDB)
if state == nil {
@ -184,8 +189,9 @@ func GetState(stateDB dbm.DB, genesisFile string) *State {
}
//--------------------------------------------------
// ABCIResponses holds intermediate state during block processing
// ABCIResponses retains the responses of the various ABCI calls during block processing.
// It is persisted to disk before calling Commit.
type ABCIResponses struct {
Height int
@ -195,6 +201,7 @@ type ABCIResponses struct {
txs types.Txs // reference for indexing results by hash
}
// NewABCIResponses returns a new ABCIResponses
func NewABCIResponses(block *types.Block) *ABCIResponses {
return &ABCIResponses{
Height: block.Height,
@ -203,14 +210,9 @@ func NewABCIResponses(block *types.Block) *ABCIResponses {
}
}
// Serialize the ABCIResponse
// Bytes serializes the ABCIResponse using go-wire
func (a *ABCIResponses) Bytes() []byte {
buf, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(*a, buf, n, err)
if *err != nil {
cmn.PanicCrisis(*err)
}
return buf.Bytes()
return wire.BinaryBytes(*a)
}
//-----------------------------------------------------------------------------


+ 2
- 2
version/version.go View File

@ -2,11 +2,11 @@ package version
const Maj = "0"
const Min = "10"
const Fix = "3"
const Fix = "4"
var (
// The full version string
Version = "0.10.3"
Version = "0.10.4"
// GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
GitCommit string


Loading…
Cancel
Save