mirror of
https://github.com/tendermint/tendermint.git
synced 2026-04-17 06:01:04 +00:00
lint: add markdown linter (#5254)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
The documentation for Tendermint Core is hosted at:
|
||||
|
||||
- https://docs.tendermint.com/master/
|
||||
- <https://docs.tendermint.com/master/>
|
||||
|
||||
built from the files in this (`/docs`) directory for
|
||||
[master](https://github.com/tendermint/tendermint/tree/master/docs) respectively.
|
||||
@@ -79,7 +79,7 @@ npm run serve
|
||||
|
||||
<!-- markdown-link-check-disable -->
|
||||
|
||||
Run `pre` and `post` hooks and start a hot-reloading web-server. See output of this command for the URL (it is often https://localhost:8080).
|
||||
Run `pre` and `post` hooks and start a hot-reloading web-server. See output of this command for the URL (it is often <https://localhost:8080>).
|
||||
|
||||
<!-- markdown-link-check-enable -->
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Make sure you [have Go installed](https://golang.org/doc/install).
|
||||
|
||||
Next, install the `abci-cli` tool and example applications:
|
||||
|
||||
```
|
||||
```sh
|
||||
mkdir -p $GOPATH/src/github.com/tendermint
|
||||
cd $GOPATH/src/github.com/tendermint
|
||||
git clone https://github.com/tendermint/tendermint.git
|
||||
@@ -25,7 +25,7 @@ make install_abci
|
||||
|
||||
Now run `abci-cli` to see the list of commands:
|
||||
|
||||
```
|
||||
```sh
|
||||
Usage:
|
||||
abci-cli [command]
|
||||
|
||||
@@ -69,7 +69,7 @@ Its code can be found
|
||||
[here](https://github.com/tendermint/tendermint/blob/master/abci/cmd/abci-cli/abci-cli.go)
|
||||
and looks like:
|
||||
|
||||
```
|
||||
```go
|
||||
func cmdKVStore(cmd *cobra.Command, args []string) error {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
|
||||
@@ -105,27 +105,27 @@ func cmdKVStore(cmd *cobra.Command, args []string) error {
|
||||
|
||||
Start by running:
|
||||
|
||||
```
|
||||
```sh
|
||||
abci-cli kvstore
|
||||
```
|
||||
|
||||
And in another terminal, run
|
||||
|
||||
```
|
||||
```sh
|
||||
abci-cli echo hello
|
||||
abci-cli info
|
||||
```
|
||||
|
||||
You'll see something like:
|
||||
|
||||
```
|
||||
```sh
|
||||
-> data: hello
|
||||
-> data.hex: 68656C6C6F
|
||||
```
|
||||
|
||||
and:
|
||||
|
||||
```
|
||||
```sh
|
||||
-> data: {"size":0}
|
||||
-> data.hex: 7B2273697A65223A307D
|
||||
```
|
||||
@@ -162,7 +162,7 @@ speaking ABCI messages to your application.
|
||||
|
||||
Try running these commands:
|
||||
|
||||
```
|
||||
```sh
|
||||
> echo hello
|
||||
-> code: OK
|
||||
-> data: hello
|
||||
@@ -226,7 +226,7 @@ Like the kvstore app, its code can be found
|
||||
[here](https://github.com/tendermint/tendermint/blob/master/abci/cmd/abci-cli/abci-cli.go)
|
||||
and looks like:
|
||||
|
||||
```
|
||||
```sh
|
||||
func cmdCounter(cmd *cobra.Command, args []string) error {
|
||||
|
||||
app := counter.NewCounterApplication(flagSerial)
|
||||
@@ -280,13 +280,13 @@ whose integer is greater than the last committed one.
|
||||
Let's kill the console and the kvstore application, and start the
|
||||
counter app:
|
||||
|
||||
```
|
||||
```sh
|
||||
abci-cli counter
|
||||
```
|
||||
|
||||
In another window, start the `abci-cli console`:
|
||||
|
||||
```
|
||||
```sh
|
||||
> set_option serial on
|
||||
-> code: OK
|
||||
-> log: OK (SetOption doesn't return anything.)
|
||||
@@ -332,7 +332,7 @@ example directory](https://github.com/tendermint/tendermint/tree/master/abci/exa
|
||||
|
||||
To run the Node.js version, fist download & install [the Javascript ABCI server](https://github.com/tendermint/js-abci):
|
||||
|
||||
```
|
||||
```sh
|
||||
git clone https://github.com/tendermint/js-abci.git
|
||||
cd js-abci
|
||||
npm install abci
|
||||
|
||||
@@ -9,7 +9,7 @@ Tendermint blockchain application.
|
||||
|
||||
The following diagram provides a superb example:
|
||||
|
||||

|
||||

|
||||
|
||||
We distinguish here between two forms of "application". The first is the
|
||||
end-user application, like a desktop-based wallet app that a user downloads,
|
||||
|
||||
@@ -26,25 +26,25 @@ 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
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- [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
|
||||
- [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
|
||||
@@ -104,7 +104,7 @@ mempool state (this behaviour can be turned off with
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
func (app *KVStoreApplication) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx {
|
||||
return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ func (app *KVStoreApplication) CheckTx(req types.RequestCheckTx) types.ResponseC
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
ResponseCheckTx requestCheckTx(RequestCheckTx req) {
|
||||
byte[] transaction = req.getTx().toByteArray();
|
||||
|
||||
@@ -170,7 +170,7 @@ merkle root of the data returned by the DeliverTx requests, or both.
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
// tx is either "key=value" or just arbitrary bytes
|
||||
func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx {
|
||||
var key, value []byte
|
||||
@@ -200,7 +200,7 @@ func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.Respo
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
/**
|
||||
* Using Protobuf types from the protoc compiler, we always start with a byte[]
|
||||
*/
|
||||
@@ -241,7 +241,7 @@ job of the [Handshake](#handshake).
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
func (app *KVStoreApplication) Commit() types.ResponseCommit {
|
||||
// Using a memdb - just return the big endian size of the db
|
||||
appHash := make([]byte, 8)
|
||||
@@ -255,7 +255,7 @@ func (app *KVStoreApplication) Commit() types.ResponseCommit {
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
ResponseCommit requestCommit(RequestCommit requestCommit) {
|
||||
|
||||
// update the internal app-state
|
||||
@@ -278,7 +278,7 @@ pick up from when it restarts. See information on the Handshake, below.
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
// Track the block hash and header information
|
||||
func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock {
|
||||
// reset valset changes
|
||||
@@ -289,7 +289,7 @@ func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock)
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
/*
|
||||
* all types come from protobuf definition
|
||||
*/
|
||||
@@ -321,7 +321,7 @@ for details on how it tracks validators.
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
// Update the validator set
|
||||
func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock {
|
||||
return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates}
|
||||
@@ -330,7 +330,7 @@ func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) typ
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
/*
|
||||
* Assume that one validator changes. The new validator has a power of 10
|
||||
*/
|
||||
@@ -367,7 +367,7 @@ Note: these query formats are subject to change!
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
if reqQuery.Prove {
|
||||
value := app.state.db.Get(prefixKey(reqQuery.Data))
|
||||
@@ -396,7 +396,7 @@ func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery type
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
ResponseQuery requestQuery(RequestQuery req) {
|
||||
final boolean isProveQuery = req.getProve();
|
||||
final ResponseQuery.Builder responseBuilder = ResponseQuery.newBuilder();
|
||||
@@ -444,7 +444,7 @@ all blocks.
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
||||
return types.ResponseInfo{
|
||||
Data: fmt.Sprintf("{\"size\":%v}", app.state.Size),
|
||||
@@ -456,7 +456,7 @@ func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.Respon
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
ResponseInfo requestInfo(RequestInfo req) {
|
||||
final byte[] lastAppHash = getLastAppHash();
|
||||
final long lastHeight = getLastHeight();
|
||||
@@ -472,7 +472,7 @@ consensus params.
|
||||
|
||||
In go:
|
||||
|
||||
```
|
||||
```go
|
||||
// Save the validators in the merkle tree
|
||||
func (app *PersistentKVStoreApplication) InitChain(req types.RequestInitChain) types.ResponseInitChain {
|
||||
for _, v := range req.Validators {
|
||||
@@ -487,7 +487,7 @@ func (app *PersistentKVStoreApplication) InitChain(req types.RequestInitChain) t
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
```java
|
||||
/*
|
||||
* all types come from protobuf definition
|
||||
*/
|
||||
|
||||
@@ -32,7 +32,7 @@ echo export GO111MODULE=on >> ~/.bash_profile
|
||||
|
||||
Then run
|
||||
|
||||
```
|
||||
```sh
|
||||
go get github.com/tendermint/tendermint
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
make tools
|
||||
@@ -55,7 +55,7 @@ full transaction bytes are stored as the key and the value.
|
||||
|
||||
Let's start a kvstore application.
|
||||
|
||||
```
|
||||
```sh
|
||||
abci-cli kvstore
|
||||
```
|
||||
|
||||
@@ -64,7 +64,7 @@ Tendermint binary installed. If not, follow the steps from
|
||||
[here](../introduction/install.md). If you have never run Tendermint
|
||||
before, use:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint init
|
||||
tendermint node
|
||||
```
|
||||
@@ -77,7 +77,7 @@ details, see [the guide on using Tendermint](../tendermint-core/using-tendermint
|
||||
You should see Tendermint making blocks! We can get the status of our
|
||||
Tendermint node as follows:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s localhost:26657/status
|
||||
```
|
||||
|
||||
@@ -86,7 +86,7 @@ tool like [jq](https://stedolan.github.io/jq/) or `json_pp`.
|
||||
|
||||
Now let's send some transactions to the kvstore.
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/broadcast_tx_commit?tx="abcd"'
|
||||
```
|
||||
|
||||
@@ -96,7 +96,7 @@ 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:
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
@@ -123,13 +123,13 @@ like:
|
||||
We can confirm that our transaction worked and the value got stored by
|
||||
querying the app:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/abci_query?data="abcd"'
|
||||
```
|
||||
|
||||
The result should look like:
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
@@ -153,14 +153,14 @@ human-readable](https://github.com/tendermint/tendermint/issues/1794).
|
||||
|
||||
Now let's try setting a different key and value:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/broadcast_tx_commit?tx="name=satoshi"'
|
||||
```
|
||||
|
||||
Now if we query for `name`, we should get `satoshi`, or `c2F0b3NoaQ==`
|
||||
in base64:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/abci_query?data="name"'
|
||||
```
|
||||
|
||||
@@ -196,13 +196,13 @@ Let's kill the previous instance of `tendermint` and the `kvstore`
|
||||
application, and start the counter app. We can enable `serial=on` with a
|
||||
flag:
|
||||
|
||||
```
|
||||
```sh
|
||||
abci-cli counter --serial
|
||||
```
|
||||
|
||||
In another window, reset then start Tendermint:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint unsafe_reset_all
|
||||
tendermint node
|
||||
```
|
||||
@@ -211,14 +211,14 @@ 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`:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl localhost:26657/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:
|
||||
|
||||
```
|
||||
```json
|
||||
> curl localhost:26657/broadcast_tx_commit?tx=0x05
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
@@ -237,7 +237,7 @@ the number `1`. If instead, we try to send a `5`, we get an error:
|
||||
|
||||
But if we send a `1`, it works again:
|
||||
|
||||
```
|
||||
```json
|
||||
> curl localhost:26657/broadcast_tx_commit?tx=0x01
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
@@ -263,7 +263,7 @@ 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:
|
||||
|
||||
```
|
||||
```sh
|
||||
git clone https://github.com/tendermint/js-abci.git
|
||||
cd js-abci
|
||||
npm install abci
|
||||
@@ -271,13 +271,13 @@ npm install abci
|
||||
|
||||
Kill the previous `counter` and `tendermint` processes. Now run the app:
|
||||
|
||||
```
|
||||
```sh
|
||||
node example/counter.js
|
||||
```
|
||||
|
||||
In another window, reset and start `tendermint`:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint unsafe_reset_all
|
||||
tendermint node
|
||||
```
|
||||
@@ -286,7 +286,7 @@ 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:
|
||||
|
||||
```
|
||||
```sh
|
||||
# ok
|
||||
curl localhost:26657/broadcast_tx_commit?tx=0x00
|
||||
# invalid nonce
|
||||
|
||||
@@ -15,7 +15,7 @@ type, only the key-value pairs defined in `EndBlock` are used.
|
||||
Each event contains a type and a list of attributes, which are key-value pairs
|
||||
denoting something about what happened during the method's execution. For more
|
||||
details on `Events`, see the
|
||||
[ABCI]https://github.com/tendermint/spec/blob/master/spec/abci/abci.md#events)
|
||||
[ABCI](https://github.com/tendermint/spec/blob/master/spec/abci/abci.md#events)
|
||||
documentation.
|
||||
|
||||
An Event has a composite key associated with it. A `compositeKey` is
|
||||
|
||||
@@ -13,14 +13,14 @@ for third-party applications (for analysis) or for inspecting state.
|
||||
To connect to a node via websocket from the CLI, you can use a tool such as
|
||||
[wscat](https://github.com/websockets/wscat) and run:
|
||||
|
||||
```
|
||||
```sh
|
||||
wscat ws://127.0.0.1:26657/websocket
|
||||
```
|
||||
|
||||
You can subscribe to any of the events above by calling the `subscribe` RPC
|
||||
method via Websocket along with a valid query.
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "subscribe",
|
||||
@@ -38,7 +38,7 @@ You can also use tags, given you had included them into DeliverTx
|
||||
response, to query transaction results. See [Indexing
|
||||
transactions](./indexing-transactions.md) for details.
|
||||
|
||||
### ValidatorSetUpdates
|
||||
## ValidatorSetUpdates
|
||||
|
||||
When validator set changes, ValidatorSetUpdates event is published. The
|
||||
event carries a list of pubkey/power pairs. The list is the same
|
||||
@@ -48,7 +48,7 @@ the ABCI spec).
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 0,
|
||||
|
||||
@@ -55,8 +55,8 @@ $ echo $GOPATH
|
||||
We'll start by creating a new Go project.
|
||||
|
||||
```bash
|
||||
$ mkdir kvstore
|
||||
$ cd kvstore
|
||||
mkdir kvstore
|
||||
cd kvstore
|
||||
```
|
||||
|
||||
Inside the example directory create a `main.go` file with the following content:
|
||||
@@ -230,7 +230,7 @@ application in 3 parts: `BeginBlock`, one `DeliverTx` per transaction and
|
||||
`EndBlock` in the end. DeliverTx are being transfered asynchronously, but the
|
||||
responses are expected to come in order.
|
||||
|
||||
```
|
||||
```go
|
||||
func (app *KVStoreApplication) BeginBlock(req abcitypes.RequestBeginBlock) abcitypes.ResponseBeginBlock {
|
||||
app.currentBatch = app.db.NewTransaction(true)
|
||||
return abcitypes.ResponseBeginBlock{}
|
||||
@@ -569,8 +569,8 @@ We are going to use [Go modules](https://github.com/golang/go/wiki/Modules) for
|
||||
dependency management.
|
||||
|
||||
```bash
|
||||
$ go mod init github.com/me/example
|
||||
$ go build
|
||||
go mod init github.com/me/example
|
||||
go build
|
||||
```
|
||||
|
||||
This should build the binary.
|
||||
@@ -625,7 +625,7 @@ Response should contain the height where this transaction was committed.
|
||||
|
||||
Now let's check if the given key now exists and its value:
|
||||
|
||||
```
|
||||
```json
|
||||
$ curl -s 'localhost:26657/abci_query?data="tendermint"'
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
|
||||
@@ -49,7 +49,7 @@ go version go1.14.x darwin/amd64
|
||||
Make sure you have `$GOPATH` environment variable set:
|
||||
|
||||
```bash
|
||||
$ echo $GOPATH
|
||||
echo $GOPATH
|
||||
/Users/melekes/go
|
||||
```
|
||||
|
||||
@@ -58,8 +58,8 @@ $ echo $GOPATH
|
||||
We'll start by creating a new Go project.
|
||||
|
||||
```bash
|
||||
$ mkdir kvstore
|
||||
$ cd kvstore
|
||||
mkdir kvstore
|
||||
cd kvstore
|
||||
```
|
||||
|
||||
Inside the example directory create a `main.go` file with the following content:
|
||||
@@ -79,7 +79,7 @@ func main() {
|
||||
When run, this should print "Hello, Tendermint Core" to the standard output.
|
||||
|
||||
```bash
|
||||
$ go run main.go
|
||||
go run main.go
|
||||
Hello, Tendermint Core
|
||||
```
|
||||
|
||||
@@ -233,7 +233,7 @@ application in 3 parts: `BeginBlock`, one `DeliverTx` per transaction and
|
||||
`EndBlock` in the end. DeliverTx are being transferred asynchronously, but the
|
||||
responses are expected to come in order.
|
||||
|
||||
```
|
||||
```go
|
||||
func (app *KVStoreApplication) BeginBlock(req abcitypes.RequestBeginBlock) abcitypes.ResponseBeginBlock {
|
||||
app.currentBatch = app.db.NewTransaction(true)
|
||||
return abcitypes.ResponseBeginBlock{}
|
||||
@@ -426,9 +426,9 @@ We are going to use [Go modules](https://github.com/golang/go/wiki/Modules) for
|
||||
dependency management.
|
||||
|
||||
```bash
|
||||
$ export GO111MODULE=on
|
||||
$ go mod init github.com/me/example
|
||||
$ go build
|
||||
export GO111MODULE=on
|
||||
go mod init github.com/me/example
|
||||
go build
|
||||
```
|
||||
|
||||
This should build the binary.
|
||||
@@ -440,8 +440,8 @@ guide](https://docs.tendermint.com/master/introduction/install.html). If you're
|
||||
installing from source, don't forget to checkout the latest release (`git checkout vX.Y.Z`).
|
||||
|
||||
```bash
|
||||
$ rm -rf /tmp/example
|
||||
$ TMHOME="/tmp/example" tendermint init
|
||||
rm -rf /tmp/example
|
||||
TMHOME="/tmp/example" tendermint init
|
||||
|
||||
I[2019-07-16|18:20:36.480] Generated private validator module=main keyFile=/tmp/example/config/priv_validator_key.json stateFile=/tmp/example2/data/priv_validator_state.json
|
||||
I[2019-07-16|18:20:36.481] Generated node key module=main path=/tmp/example/config/node_key.json
|
||||
@@ -455,8 +455,8 @@ Feel free to explore the generated files, which can be found at
|
||||
We are ready to start our application:
|
||||
|
||||
```bash
|
||||
$ rm example.sock
|
||||
$ ./example
|
||||
rm example.sock
|
||||
./example
|
||||
|
||||
badger 2019/07/16 18:25:11 INFO: All 0 tables opened in 0s
|
||||
badger 2019/07/16 18:25:11 INFO: Replaying file id: 0 at offset: 0
|
||||
@@ -468,7 +468,7 @@ Then we need to start Tendermint Core and point it to our application. Staying
|
||||
within the application directory execute:
|
||||
|
||||
```bash
|
||||
$ TMHOME="/tmp/example" tendermint node --proxy_app=unix://example.sock
|
||||
TMHOME="/tmp/example" tendermint node --proxy_app=unix://example.sock
|
||||
|
||||
I[2019-07-16|18:26:20.362] Version info module=main software=0.32.1 block=10 p2p=7
|
||||
I[2019-07-16|18:26:20.383] Starting Node module=main impl=Node
|
||||
@@ -480,7 +480,7 @@ I[2019-07-16|18:26:21.446] Committed state module=s
|
||||
|
||||
This should start the full node and connect to our ABCI application.
|
||||
|
||||
```
|
||||
```sh
|
||||
I[2019-07-16|18:25:11.525] Waiting for new connection...
|
||||
I[2019-07-16|18:26:20.329] Accepted a new connection
|
||||
I[2019-07-16|18:26:20.329] Waiting for new connection...
|
||||
@@ -491,8 +491,8 @@ I[2019-07-16|18:26:20.330] Accepted a new connection
|
||||
|
||||
Now open another tab in your terminal and try sending a transaction:
|
||||
|
||||
```bash
|
||||
$ curl -s 'localhost:26657/broadcast_tx_commit?tx="tendermint=rocks"'
|
||||
```json
|
||||
curl -s 'localhost:26657/broadcast_tx_commit?tx="tendermint=rocks"'
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
@@ -510,8 +510,8 @@ Response should contain the height where this transaction was committed.
|
||||
|
||||
Now let's check if the given key now exists and its value:
|
||||
|
||||
```
|
||||
$ curl -s 'localhost:26657/abci_query?data="tendermint"'
|
||||
```json
|
||||
curl -s 'localhost:26657/abci_query?data="tendermint"'
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
|
||||
@@ -64,9 +64,9 @@ For Gradle installation, please refer to [their official guide](https://gradle.o
|
||||
We'll start by creating a new Gradle project.
|
||||
|
||||
```bash
|
||||
$ export KVSTORE_HOME=~/kvstore
|
||||
$ mkdir $KVSTORE_HOME
|
||||
$ cd $KVSTORE_HOME
|
||||
export KVSTORE_HOME=~/kvstore
|
||||
mkdir $KVSTORE_HOME
|
||||
cd $KVSTORE_HOME
|
||||
```
|
||||
|
||||
Inside the example directory run:
|
||||
|
||||
@@ -41,7 +41,7 @@ Please refer to [the Oracle's guide for installing JDK](https://www.oracle.com/t
|
||||
Verify that you have installed Java successfully:
|
||||
|
||||
```bash
|
||||
$ java -version
|
||||
java -version
|
||||
java version "1.8.0_162"
|
||||
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
|
||||
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)
|
||||
@@ -53,7 +53,7 @@ In my case it is Java SE Development Kit 8.
|
||||
Make sure you have `$JAVA_HOME` environment variable set:
|
||||
|
||||
```bash
|
||||
$ echo $JAVA_HOME
|
||||
echo $JAVA_HOME
|
||||
/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home
|
||||
```
|
||||
|
||||
@@ -64,9 +64,9 @@ For Gradle installation, please refer to [their official guide](https://gradle.o
|
||||
We'll start by creating a new Gradle project.
|
||||
|
||||
```bash
|
||||
$ export KVSTORE_HOME=~/kvstore
|
||||
$ mkdir $KVSTORE_HOME
|
||||
$ cd $KVSTORE_HOME
|
||||
export KVSTORE_HOME=~/kvstore
|
||||
mkdir $KVSTORE_HOME
|
||||
cd $KVSTORE_HOME
|
||||
```
|
||||
|
||||
Inside the example directory run:
|
||||
@@ -78,7 +78,7 @@ gradle init --dsl groovy --package io.example --project-name example --type kotl
|
||||
This will create a new project for you. The tree of files should look like:
|
||||
|
||||
```bash
|
||||
$ tree
|
||||
tree
|
||||
.
|
||||
|-- build.gradle
|
||||
|-- gradle
|
||||
@@ -106,7 +106,7 @@ $ tree
|
||||
When run, this should print "Hello world." to the standard output.
|
||||
|
||||
```bash
|
||||
$ ./gradlew run
|
||||
./gradlew run
|
||||
> Task :run
|
||||
Hello world.
|
||||
```
|
||||
@@ -214,7 +214,7 @@ To generate all protobuf-type classes run:
|
||||
To verify that everything went smoothly, you can inspect the `build/generated/` directory:
|
||||
|
||||
```bash
|
||||
$ tree build/generated/
|
||||
tree build/generated/
|
||||
build/generated/
|
||||
`-- source
|
||||
`-- proto
|
||||
@@ -521,10 +521,10 @@ execute `tendermint init`. But before we do that, we will need to install
|
||||
Tendermint Core.
|
||||
|
||||
```bash
|
||||
$ rm -rf /tmp/example
|
||||
$ cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
$ make install
|
||||
$ TMHOME="/tmp/example" tendermint init
|
||||
rm -rf /tmp/example
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
make install
|
||||
TMHOME="/tmp/example" tendermint init
|
||||
|
||||
I[2019-07-16|18:20:36.480] Generated private validator module=main keyFile=/tmp/example/config/priv_validator_key.json stateFile=/tmp/example2/data/priv_validator_state.json
|
||||
I[2019-07-16|18:20:36.481] Generated node key module=main path=/tmp/example/config/node_key.json
|
||||
@@ -547,7 +547,7 @@ Then we need to start Tendermint Core and point it to our application. Staying
|
||||
within the application directory execute:
|
||||
|
||||
```bash
|
||||
$ TMHOME="/tmp/example" tendermint node --abci grpc --proxy_app tcp://127.0.0.1:26658
|
||||
TMHOME="/tmp/example" tendermint node --abci grpc --proxy_app tcp://127.0.0.1:26658
|
||||
|
||||
I[2019-07-28|15:44:53.632] Version info module=main software=0.32.1 block=10 p2p=7
|
||||
I[2019-07-28|15:44:53.677] Starting Node module=main impl=Node
|
||||
@@ -559,7 +559,7 @@ I[2019-07-28|15:44:54.814] Committed state module=s
|
||||
Now open another tab in your terminal and try sending a transaction:
|
||||
|
||||
```bash
|
||||
$ curl -s 'localhost:26657/broadcast_tx_commit?tx="tendermint=rocks"'
|
||||
curl -s 'localhost:26657/broadcast_tx_commit?tx="tendermint=rocks"'
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
@@ -578,7 +578,7 @@ Response should contain the height where this transaction was committed.
|
||||
Now let's check if the given key now exists and its value:
|
||||
|
||||
```bash
|
||||
$ curl -s 'localhost:26657/abci_query?data="tendermint"'
|
||||
curl -s 'localhost:26657/abci_query?data="tendermint"'
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
|
||||
@@ -226,7 +226,7 @@ is inspired by Raft, is that it's simpler so normal engineers could understand.
|
||||
|
||||
**CC**: Can you expand on the termination requirement?
|
||||
|
||||
_Important point about Liveness in Tendermint_
|
||||
> **Important point about Liveness in Tendermint**
|
||||
|
||||
**ZM**: In Tendermint, we are saying, for termination, we are making assumption
|
||||
that the system is partially synchronous. And in a partially synchronous system
|
||||
|
||||
@@ -15,6 +15,6 @@ Get Tendermint up-and-running quickly with the [quick-start guide](./quick-start
|
||||
|
||||
Detailed [installation instructions](./install.md).
|
||||
|
||||
## What is Tendermint?
|
||||
## What is Tendermint
|
||||
|
||||
Dive into [what Tendermint is and why](./what-is-tendermint.md)!
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Tendermint Architectural Overview
|
||||
_November 2019_
|
||||
|
||||
> **November 2019**
|
||||
|
||||
Over the next few weeks, @brapse, @marbar3778 and I (@tessr) are having a series of meetings to go over the architecture of Tendermint Core. These are my notes from these meetings, which will either serve as an artifact for onboarding future engineers; or will provide the basis for such a document.
|
||||
|
||||
## Communication
|
||||
|
||||
There are three forms of communication (e.g., requests, responses, connections) that can happen in Tendermint Core: *internode communication*, *intranode communication*, and *client communication*.
|
||||
|
||||
- Internode communication: Happens between a node and other peers. This kind of communication happens over TCP or HTTP. More on this below.
|
||||
- Intranode communication: Happens within the node itself (i.e., between reactors or other components). These are typically function or method calls, or occasionally happen through an event bus.
|
||||
- Client communiation: Happens between a client (like a wallet or a browser) and a node on the network.
|
||||
@@ -13,6 +15,7 @@ There are three forms of communication (e.g., requests, responses, connections)
|
||||
### Internode Communication
|
||||
|
||||
Internode communication can happen in two ways:
|
||||
|
||||
1. TCP connections through the p2p package
|
||||
- Most common form of internode communication
|
||||
- Connections between nodes are persisted and shared across reactors, facilitated by the switch. (More on the switch below.)
|
||||
@@ -24,10 +27,12 @@ Internode communication can happen in two ways:
|
||||
### P2P Business (the Switch, the PEX, and the Address Book)
|
||||
|
||||
When writing a p2p service, there are two primary responsibilities:
|
||||
|
||||
1. Routing: Who gets which messages?
|
||||
2. Peer management: Who can you talk to? What is their state? And how can you do peer discovery?
|
||||
|
||||
The first responsibility is handled by the Switch:
|
||||
|
||||
- Responsible for routing connections between peers
|
||||
- Notably _only handles TCP connections_; RPC/HTTP is separate
|
||||
- Is a dependency for every reactor; all reactors expose a function `setSwitch`
|
||||
@@ -42,12 +47,14 @@ The second responsibility is handled by a combination of the PEX and the Address
|
||||
TODO: What is the PEX and the Address Book?
|
||||
|
||||
#### The Nature of TCP, and Introduction to the `mconnection`
|
||||
Here are some relevant facts about TCP:
|
||||
1. All TCP connections have a "frame window size" which represents the packet size to the "confidence;" i.e., if you are sending packets along a new connection, you must start out with small packets. As the packets are received successfully, you can start to send larger and larger packets. (This curve is illustrated below.) This means that TCP connections are slow to spin up.
|
||||
3. The syn/ack process also means that there's a high overhead for small, frequent messages
|
||||
4. Sockets are represented by file descriptors.
|
||||
|
||||

|
||||
Here are some relevant facts about TCP:
|
||||
|
||||
1. All TCP connections have a "frame window size" which represents the packet size to the "confidence;" i.e., if you are sending packets along a new connection, you must start out with small packets. As the packets are received successfully, you can start to send larger and larger packets. (This curve is illustrated below.) This means that TCP connections are slow to spin up.
|
||||
2. The syn/ack process also means that there's a high overhead for small, frequent messages
|
||||
3. Sockets are represented by file descriptors.
|
||||
|
||||

|
||||
|
||||
In order to have performant TCP connections under the conditions created in Tendermint, we've created the `mconnection`, or the multiplexing connection. It is our own protocol built on top of TCP. It lets us reuse TCP connections to minimize overhead, and it keeps the window size high by sending auxiliary messages when necessary.
|
||||
|
||||
@@ -57,22 +64,25 @@ The `mconnection` has two methods: `send`, which takes a raw handle to the socke
|
||||
|
||||
The `mconnection` is owned by a peer, which is owned (potentially with many other peers) by a (global) transport, which is owned by the (global) switch:
|
||||
|
||||
<!-- markdownlint-disable -->
|
||||
```
|
||||
switch
|
||||
transport
|
||||
peer
|
||||
mconnection
|
||||
peer
|
||||
mconnection
|
||||
peer
|
||||
mconnection
|
||||
transport
|
||||
peer
|
||||
mconnection
|
||||
peer
|
||||
mconnection
|
||||
peer
|
||||
mconnection
|
||||
```
|
||||
<!-- markdownlint-restore -->
|
||||
|
||||
## node.go
|
||||
|
||||
node.go is the entrypoint for running a node. It sets up reactors, sets up the switch, and registers all the RPC endpoints for a node.
|
||||
|
||||
## Types of Nodes
|
||||
|
||||
1. Validator Node:
|
||||
2. Full Node:
|
||||
3. Seed Node:
|
||||
@@ -82,6 +92,7 @@ TODO: Flesh out the differences between the types of nodes and how they're confi
|
||||
## Reactors
|
||||
|
||||
Here are some Reactor Facts:
|
||||
|
||||
- Every reactor holds a pointer to the global switch (set through `SetSwitch()`)
|
||||
- The switch holds a pointer to every reactor (`addReactor()`)
|
||||
- Every reactor gets set up in node.go (and if you are using custom reactors, this is where you specify that)
|
||||
@@ -90,6 +101,7 @@ Here are some Reactor Facts:
|
||||
- Sometimes reactors talk to each other by fetching references to one another via the switch (which maintains a pointer to each reactor). **Question: Can reactors talk to each other in any other way?**
|
||||
|
||||
Furthermore, all reactors expose:
|
||||
|
||||
1. A TCP channel
|
||||
2. A `receive` method
|
||||
3. An `addReactor` call
|
||||
@@ -99,6 +111,7 @@ The `receive` method can be called many times by the mconnection. It has the sam
|
||||
The `addReactor` call does a for loop over all the channels on the reactor and creates a map of channel IDs->reactors. The switch holds onto this map, and passes it to the _transport_, a thin wrapper around TCP connections.
|
||||
|
||||
The following is an exhaustive (?) list of reactors:
|
||||
|
||||
- Blockchain Reactor
|
||||
- Consensus Reactor
|
||||
- Evidence Reactor
|
||||
@@ -108,6 +121,8 @@ The following is an exhaustive (?) list of reactors:
|
||||
Each of these will be discussed in more detail later.
|
||||
|
||||
### Blockchain Reactor
|
||||
|
||||
The blockchain reactor has two responsibilities:
|
||||
|
||||
1. Serve blocks at the request of peers
|
||||
2. TODO: learn about the second responsibility of the blockchain reactor
|
||||
2. TODO: learn about the second responsibility of the blockchain reactor
|
||||
|
||||
@@ -21,7 +21,7 @@ echo export GO111MODULE=on >> ~/.bash_profile
|
||||
|
||||
### Get Source Code
|
||||
|
||||
```
|
||||
```sh
|
||||
mkdir -p $GOPATH/src/github.com/tendermint
|
||||
cd $GOPATH/src/github.com/tendermint
|
||||
git clone https://github.com/tendermint/tendermint.git
|
||||
@@ -30,19 +30,19 @@ cd tendermint
|
||||
|
||||
### Get Tools & Dependencies
|
||||
|
||||
```
|
||||
```sh
|
||||
make tools
|
||||
```
|
||||
|
||||
### Compile
|
||||
|
||||
```
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
|
||||
to put the binary in `$GOPATH/bin` or use:
|
||||
|
||||
```
|
||||
```sh
|
||||
make build
|
||||
```
|
||||
|
||||
@@ -56,7 +56,7 @@ file.
|
||||
The latest tendermint is now installed. You can verify the installation by
|
||||
running:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint version
|
||||
```
|
||||
|
||||
@@ -64,7 +64,7 @@ tendermint version
|
||||
|
||||
To start a one-node blockchain with a simple in-process application:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint init
|
||||
tendermint node --proxy_app=kvstore
|
||||
```
|
||||
@@ -73,14 +73,14 @@ tendermint node --proxy_app=kvstore
|
||||
|
||||
If you already have Tendermint installed, and you make updates, simply
|
||||
|
||||
```
|
||||
```sh
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
make install
|
||||
```
|
||||
|
||||
To upgrade, run
|
||||
|
||||
```
|
||||
```sh
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
git pull origin master
|
||||
make install
|
||||
@@ -92,7 +92,7 @@ Install [LevelDB](https://github.com/google/leveldb) (minimum version is 1.7).
|
||||
|
||||
Install LevelDB with snappy (optionally). Below are commands for Ubuntu:
|
||||
|
||||
```
|
||||
```sh
|
||||
sudo apt-get update
|
||||
sudo apt install build-essential
|
||||
|
||||
@@ -111,20 +111,20 @@ wget https://github.com/google/leveldb/archive/v1.20.tar.gz && \
|
||||
|
||||
Set a database backend to `cleveldb`:
|
||||
|
||||
```
|
||||
```toml
|
||||
# config/config.toml
|
||||
db_backend = "cleveldb"
|
||||
```
|
||||
|
||||
To install Tendermint, run:
|
||||
|
||||
```
|
||||
```sh
|
||||
CGO_LDFLAGS="-lsnappy" make install TENDERMINT_BUILD_OPTIONS=cleveldb
|
||||
```
|
||||
|
||||
or run:
|
||||
|
||||
```
|
||||
```sh
|
||||
CGO_LDFLAGS="-lsnappy" make build TENDERMINT_BUILD_OPTIONS=cleveldb
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ order: 2
|
||||
|
||||
## Overview
|
||||
|
||||
This is a quick start guide. If you have a vague idea about how <df value="tendermint">Tendermint</df>
|
||||
This is a quick start guide. If you have a vague idea about how Tendermint
|
||||
works and want to get started right away, continue.
|
||||
|
||||
## Install
|
||||
@@ -18,7 +18,7 @@ Ubuntu 16.04 machine, use [this script](https://git.io/fFfOR).
|
||||
|
||||
WARNING: do not run this on your local machine.
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -L https://git.io/fFfOR | bash
|
||||
source ~/.profile
|
||||
```
|
||||
@@ -33,7 +33,7 @@ For manual installation, see the [install instructions](install.md)
|
||||
|
||||
Running:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint init
|
||||
```
|
||||
|
||||
@@ -41,7 +41,7 @@ will create the required files for a single, local node.
|
||||
|
||||
These files are found in `$HOME/.tendermint`:
|
||||
|
||||
```
|
||||
```sh
|
||||
$ ls $HOME/.tendermint
|
||||
|
||||
config data
|
||||
@@ -58,46 +58,46 @@ Configuring a cluster is covered further below.
|
||||
|
||||
Start tendermint with a simple in-process application:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint node --proxy_app=kvstore
|
||||
```
|
||||
|
||||
and blocks will start to stream in:
|
||||
|
||||
```
|
||||
```sh
|
||||
I[01-06|01:45:15.592] Executed block module=state height=1 validTxs=0 invalidTxs=0
|
||||
I[01-06|01:45:15.624] Committed state module=state height=1 txs=0 appHash=
|
||||
```
|
||||
|
||||
Check the status with:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s localhost:26657/status
|
||||
```
|
||||
|
||||
### Sending Transactions
|
||||
|
||||
With the kvstore app running, we can send transactions:
|
||||
With the KVstore app running, we can send transactions:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/broadcast_tx_commit?tx="abcd"'
|
||||
```
|
||||
|
||||
and check that it worked with:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/abci_query?data="abcd"'
|
||||
```
|
||||
|
||||
We can send transactions with a key and value too:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/broadcast_tx_commit?tx="name=satoshi"'
|
||||
```
|
||||
|
||||
and query the key:
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -s 'localhost:26657/abci_query?data="name"'
|
||||
```
|
||||
|
||||
@@ -111,7 +111,7 @@ addresses below as IP1, IP2, IP3, IP4.
|
||||
|
||||
Then, `ssh` into each machine, and execute [this script](https://git.io/fFfOR):
|
||||
|
||||
```
|
||||
```sh
|
||||
curl -L https://git.io/fFfOR | bash
|
||||
source ~/.profile
|
||||
```
|
||||
@@ -122,7 +122,7 @@ Next, use the `tendermint testnet` command to create four directories of config
|
||||
|
||||
Before you can start the network, you'll need peers identifiers (IPs are not enough and can change). We'll refer to them as ID1, ID2, ID3, ID4.
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint show_node_id --home ./mytestnet/node0
|
||||
tendermint show_node_id --home ./mytestnet/node1
|
||||
tendermint show_node_id --home ./mytestnet/node2
|
||||
@@ -131,7 +131,7 @@ tendermint show_node_id --home ./mytestnet/node3
|
||||
|
||||
Finally, from each machine, run:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint node --home ./mytestnet/node0 --proxy_app=kvstore --p2p.persistent_peers="ID1@IP1:26656,ID2@IP2:26656,ID3@IP3:26656,ID4@IP4:26656"
|
||||
tendermint node --home ./mytestnet/node1 --proxy_app=kvstore --p2p.persistent_peers="ID1@IP1:26656,ID2@IP2:26656,ID3@IP3:26656,ID4@IP4:26656"
|
||||
tendermint node --home ./mytestnet/node2 --proxy_app=kvstore --p2p.persistent_peers="ID1@IP1:26656,ID2@IP2:26656,ID3@IP3:26656,ID4@IP4:26656"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
order: 4
|
||||
---
|
||||
|
||||
# What is Tendermint?
|
||||
# What is Tendermint
|
||||
|
||||
Tendermint is software for securely and consistently replicating an
|
||||
application on many machines. By securely, we mean that Tendermint works
|
||||
@@ -74,7 +74,7 @@ Tendermint is in essence similar software, but with two key differences:
|
||||
the application logic that's right for them, from key-value store to
|
||||
cryptocurrency to e-voting platform and beyond.
|
||||
|
||||
### Bitcoin, Ethereum, etc.
|
||||
### Bitcoin, Ethereum, etc
|
||||
|
||||
Tendermint emerged in the tradition of cryptocurrencies like Bitcoin,
|
||||
Ethereum, etc. with the goal of providing a more efficient and secure
|
||||
@@ -227,7 +227,7 @@ 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.
|
||||
|
||||

|
||||

|
||||
|
||||
## A Note on Determinism
|
||||
|
||||
@@ -263,7 +263,7 @@ Tendermint is an easy-to-understand, mostly asynchronous, BFT consensus
|
||||
protocol. The protocol follows a simple state machine that looks like
|
||||
this:
|
||||
|
||||

|
||||

|
||||
|
||||
Participants in the protocol are called **validators**; they take turns
|
||||
proposing blocks of transactions and voting on them. Blocks are
|
||||
@@ -329,4 +329,4 @@ The following diagram is Tendermint in a (technical) nutshell. [See here
|
||||
for high resolution
|
||||
version](https://github.com/mobfoundry/hackatom/blob/master/tminfo.pdf).
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -61,7 +61,7 @@ the binary and config files to the container.
|
||||
|
||||
To change the number of validators / non-validators change the `localnet-start` Makefile target [here](../../makefile):
|
||||
|
||||
```sh
|
||||
```makefile
|
||||
localnet-start: localnet-stop
|
||||
@if ! [ -f build/node0/config/genesis.json ]; then docker run --rm -v $(CURDIR)/build:/tendermint:Z tendermint/localnode testnet --v 5 --n 3 --o . --populate-persistent-peers --starting-ip-address 192.167.10.2 ; fi
|
||||
docker-compose up
|
||||
|
||||
@@ -28,7 +28,7 @@ node testnet. The script more or less does everything described below.
|
||||
- Create SSH keys (`ssh-keygen`)
|
||||
- Set environment variables:
|
||||
|
||||
```
|
||||
```sh
|
||||
export DO_API_TOKEN="abcdef01234567890abcdef01234567890"
|
||||
export SSH_KEY_FILE="$HOME/.ssh/id_rsa.pub"
|
||||
```
|
||||
@@ -40,13 +40,13 @@ These will be used by both `terraform` and `ansible`.
|
||||
This step will create four Digital Ocean droplets. First, go to the
|
||||
correct directory:
|
||||
|
||||
```
|
||||
```sh
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint/networks/remote/terraform
|
||||
```
|
||||
|
||||
then:
|
||||
|
||||
```
|
||||
```sh
|
||||
terraform init
|
||||
terraform apply -var DO_API_TOKEN="$DO_API_TOKEN" -var SSH_KEY_FILE="$SSH_KEY_FILE"
|
||||
```
|
||||
@@ -72,13 +72,13 @@ number of droplets created).
|
||||
|
||||
To create the node files run:
|
||||
|
||||
```
|
||||
```sh
|
||||
tendermint testnet
|
||||
```
|
||||
|
||||
Then, to configure our droplets run:
|
||||
|
||||
```
|
||||
```sh
|
||||
ansible-playbook -i inventory/digital_ocean.py -l sentrynet config.yml -e BINARY=$GOPATH/src/github.com/tendermint/tendermint/build/tendermint -e CONFIGDIR=$GOPATH/src/github.com/tendermint/tendermint/networks/remote/ansible/mytestnet
|
||||
```
|
||||
|
||||
@@ -87,7 +87,7 @@ configuration files to run a testnet.
|
||||
|
||||
Next, we run the install role:
|
||||
|
||||
```
|
||||
```sh
|
||||
ansible-playbook -i inventory/digital_ocean.py -l sentrynet install.yml
|
||||
```
|
||||
|
||||
@@ -104,14 +104,14 @@ increasing).
|
||||
Next, open `roles/install/templates/systemd.service.j2` and look for the
|
||||
line `ExecStart` which should look something like:
|
||||
|
||||
```
|
||||
```sh
|
||||
ExecStart=/usr/bin/tendermint node --proxy_app=kvstore
|
||||
```
|
||||
|
||||
and add the `--p2p.persistent_peers` flag with the relevant information
|
||||
for each node. The resulting file should look something like:
|
||||
|
||||
```
|
||||
```sh
|
||||
[Unit]
|
||||
Description={{service}}
|
||||
Requires=network-online.target
|
||||
@@ -132,13 +132,13 @@ WantedBy=multi-user.target
|
||||
|
||||
Then, stop the nodes:
|
||||
|
||||
```
|
||||
```sh
|
||||
ansible-playbook -i inventory/digital_ocean.py -l sentrynet stop.yml
|
||||
```
|
||||
|
||||
Finally, we run the install role again:
|
||||
|
||||
```
|
||||
```sh
|
||||
ansible-playbook -i inventory/digital_ocean.py -l sentrynet install.yml
|
||||
```
|
||||
|
||||
@@ -148,7 +148,7 @@ increasing. Your testnet is now up and running :)
|
||||
|
||||
Peek at the logs with the status role:
|
||||
|
||||
```
|
||||
```sh
|
||||
ansible-playbook -i inventory/digital_ocean.py -l sentrynet status.yml
|
||||
```
|
||||
|
||||
@@ -160,7 +160,7 @@ service provider. You can set up your nodes to log there automatically.
|
||||
Create an account and get your API key from the notes on [this
|
||||
page](https://app.logz.io/#/dashboard/data-sources/Filebeat), then:
|
||||
|
||||
```
|
||||
```sh
|
||||
yum install systemd-devel || echo "This will only work on RHEL-based systems."
|
||||
apt-get install libsystemd-dev || echo "This will only work on Debian-based systems."
|
||||
|
||||
@@ -172,6 +172,6 @@ ansible-playbook -i inventory/digital_ocean.py -l sentrynet logzio.yml -e LOGZIO
|
||||
|
||||
To remove your droplets, run:
|
||||
|
||||
```
|
||||
```sh
|
||||
terraform destroy -var DO_API_TOKEN="$DO_API_TOKEN" -var SSH_KEY_FILE="$SSH_KEY_FILE"
|
||||
```
|
||||
|
||||
@@ -16,7 +16,7 @@ the parameters set with their default values. It will look something
|
||||
like the file below, however, double check by inspecting the
|
||||
`config.toml` created with your version of `tendermint` installed:
|
||||
|
||||
```
|
||||
```toml
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
@@ -351,13 +351,13 @@ namespace = "tendermint"
|
||||
|
||||
## Empty blocks VS no empty blocks
|
||||
|
||||
**create_empty_blocks = true**
|
||||
### create_empty_blocks = true
|
||||
|
||||
If `create_empty_blocks` is set to `true` in your config, blocks will be
|
||||
created ~ every second (with default consensus parameters). You can regulate
|
||||
the delay between blocks by changing the `timeout_commit`. E.g. `timeout_commit = "10s"` should result in ~ 10 second blocks.
|
||||
|
||||
**create_empty_blocks = false**
|
||||
### create_empty_blocks = false
|
||||
|
||||
In this setting, blocks are created when transactions received.
|
||||
|
||||
@@ -386,7 +386,7 @@ production](./running-in-production.md)
|
||||
You can also find more detailed technical explanation in the spec: [The latest
|
||||
gossip on BFT consensus](https://arxiv.org/abs/1807.04938).
|
||||
|
||||
```
|
||||
```toml
|
||||
[consensus]
|
||||
...
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ order: 7
|
||||
We first create three connections (mempool, consensus and query) to the
|
||||
application (running `kvstore` locally in this case).
|
||||
|
||||
```
|
||||
```sh
|
||||
I[10-04|13:54:27.364] Starting multiAppConn module=proxy impl=multiAppConn
|
||||
I[10-04|13:54:27.366] Starting localClient module=abci-client connection=query impl=localClient
|
||||
I[10-04|13:54:27.366] Starting localClient module=abci-client connection=mempool impl=localClient
|
||||
@@ -18,7 +18,7 @@ I[10-04|13:54:27.367] Starting localClient module=abci-c
|
||||
|
||||
Then Tendermint Core and the application perform a handshake.
|
||||
|
||||
```
|
||||
```sh
|
||||
I[10-04|13:54:27.367] ABCI Handshake module=consensus appHeight=90 appHash=E0FBAFBF6FCED8B9786DDFEB1A0D4FA2501BADAD
|
||||
I[10-04|13:54:27.368] ABCI Replay Blocks module=consensus appHeight=90 storeHeight=90 stateHeight=90
|
||||
I[10-04|13:54:27.368] Completed ABCI Handshake - Tendermint and App are synced module=consensus appHeight=90 appHash=E0FBAFBF6FCED8B9786DDFEB1A0D4FA2501BADAD
|
||||
@@ -27,7 +27,7 @@ I[10-04|13:54:27.368] Completed ABCI Handshake - Tendermint and App are synced m
|
||||
After that, we start a few more things like the event switch, reactors,
|
||||
and perform UPNP discover in order to detect the IP address.
|
||||
|
||||
```
|
||||
```sh
|
||||
I[10-04|13:54:27.374] Starting EventSwitch module=types impl=EventSwitch
|
||||
I[10-04|13:54:27.375] This node is a validator module=consensus
|
||||
I[10-04|13:54:27.379] Starting Node module=main impl=Node
|
||||
@@ -50,7 +50,7 @@ validator". It also could be just an observer (regular node).
|
||||
|
||||
Next we replay all the messages from the WAL.
|
||||
|
||||
```
|
||||
```sh
|
||||
I[10-04|13:54:30.390] Catchup by replaying consensus messages module=consensus height=91
|
||||
I[10-04|13:54:30.390] Replay: New Step module=consensus height=91 round=0 step=RoundStepNewHeight
|
||||
I[10-04|13:54:30.390] Replay: Done module=consensus
|
||||
@@ -58,7 +58,7 @@ I[10-04|13:54:30.390] Replay: Done module=consen
|
||||
|
||||
"Started node" message signals that everything is ready for work.
|
||||
|
||||
```
|
||||
```sh
|
||||
I[10-04|13:54:30.391] Starting RPC HTTP server on tcp socket 0.0.0.0:26657 module=rpc-server
|
||||
I[10-04|13:54:30.392] Started node module=main nodeInfo="NodeInfo{id: DF22D7C92C91082324A1312F092AA1DA197FA598DBBFB6526E, moniker: anonymous, network: test-chain-3MNw2N [remote , listen 10.0.2.15:26656], version: 0.11.0-10f361fc ([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:26657])}"
|
||||
```
|
||||
@@ -69,7 +69,7 @@ precommits and finally have a chance to commit a block. For details,
|
||||
please refer to [Byzantine Consensus
|
||||
Algorithm](https://github.com/tendermint/spec/blob/master/spec/consensus/consensus.md).
|
||||
|
||||
```
|
||||
```sh
|
||||
I[10-04|13:54:30.393] enterNewRound(91/0). Current: 91/0/RoundStepNewHeight module=consensus
|
||||
I[10-04|13:54:30.393] enterPropose(91/0). Current: 91/0/RoundStepNewRound module=consensus
|
||||
I[10-04|13:54:30.393] enterPropose: Our turn to propose module=consensus proposer=125B0E3C5512F5C2B0E1109E31885C4511570C42 privValidator="PrivValidator{125B0E3C5512F5C2B0E1109E31885C4511570C42 LH:90, LR:0, LS:3}"
|
||||
|
||||
@@ -31,9 +31,9 @@ proofs](https://github.com/tendermint/spec/blob/953523c3cb99fdb8c8f7a2d21e3a9909
|
||||
name-registry without worrying about fork censorship attacks, without posting
|
||||
a commit and waiting for confirmations. It's fast, secure, and free!
|
||||
|
||||
## Where to obtain trusted height & hash?
|
||||
## Where to obtain trusted height & hash
|
||||
|
||||
https://pkg.go.dev/github.com/tendermint/tendermint/light?tab=doc#TrustOptions
|
||||
<https://pkg.go.dev/github.com/tendermint/tendermint/light?tab=doc#TrustOptions>
|
||||
|
||||
One way to obtain semi-trusted hash & height is to query multiple full nodes
|
||||
and compare their hashes:
|
||||
|
||||
@@ -12,31 +12,34 @@ arrived (via RPC or from other nodes).
|
||||
So the only way to specify the order is to send them to a single node.
|
||||
|
||||
valA:
|
||||
- tx1
|
||||
- tx2
|
||||
- tx3
|
||||
|
||||
- tx1
|
||||
- tx2
|
||||
- tx3
|
||||
|
||||
If the transactions are split up across different nodes, there's no way to
|
||||
ensure they are processed in the expected order.
|
||||
|
||||
valA:
|
||||
- tx1
|
||||
- tx2
|
||||
|
||||
- tx1
|
||||
- tx2
|
||||
|
||||
valB:
|
||||
- tx3
|
||||
|
||||
- tx3
|
||||
|
||||
If valB is the proposer, the order might be:
|
||||
|
||||
- tx3
|
||||
- tx1
|
||||
- tx2
|
||||
- tx3
|
||||
- tx1
|
||||
- tx2
|
||||
|
||||
If valA is the proposer, the order might be:
|
||||
|
||||
- tx1
|
||||
- tx2
|
||||
- tx3
|
||||
- tx1
|
||||
- tx2
|
||||
- tx3
|
||||
|
||||
That said, if the transactions contain some internal value, like an
|
||||
order/nonce/sequence number, the application can reject transactions that are
|
||||
|
||||
@@ -54,6 +54,6 @@ The following metrics are available:
|
||||
|
||||
Percentage of missing + byzantine validators:
|
||||
|
||||
```
|
||||
```md
|
||||
((consensus\_byzantine\_validators\_power + consensus\_missing\_validators\_power) / consensus\_validators\_power) * 100
|
||||
```
|
||||
|
||||
@@ -165,7 +165,7 @@ Tendermint also can report and serve Prometheus metrics. See
|
||||
information into an archive. See [Debugging](../tools/debugging.md) for more
|
||||
information.
|
||||
|
||||
## What happens when my app dies?
|
||||
## What happens when my app dies
|
||||
|
||||
You are supposed to run Tendermint under a [process
|
||||
supervisor](https://en.wikipedia.org/wiki/Process_supervision) (like
|
||||
@@ -180,7 +180,7 @@ order of restart does not matter for it.
|
||||
## Signal handling
|
||||
|
||||
We catch SIGINT and SIGTERM and try to clean up nicely. For other
|
||||
signals we use the default behaviour in Go: [Default behavior of signals
|
||||
signals we use the default behavior in Go: [Default behavior of signals
|
||||
in Go
|
||||
programs](https://golang.org/pkg/os/signal/#hdr-Default_behavior_of_signals_in_Go_programs).
|
||||
|
||||
@@ -206,11 +206,11 @@ Other causes can be:
|
||||
- Operating system bugs
|
||||
- Admin error (e.g., directly modifying Tendermint data-directory contents)
|
||||
|
||||
(Source: https://wiki.postgresql.org/wiki/Corruption)
|
||||
(Source: <https://wiki.postgresql.org/wiki/Corruption>)
|
||||
|
||||
### WAL Corruption
|
||||
|
||||
If consensus WAL is corrupted at the lastest height and you are trying to start
|
||||
If consensus WAL is corrupted at the latest height and you are trying to start
|
||||
Tendermint, replay will fail with panic.
|
||||
|
||||
Recovering from data corruption can be hard and time-consuming. Here are two approaches you can take:
|
||||
@@ -220,33 +220,33 @@ Recovering from data corruption can be hard and time-consuming. Here are two app
|
||||
|
||||
1) Create a backup of the corrupted WAL file:
|
||||
|
||||
```
|
||||
cp "$TMHOME/data/cs.wal/wal" > /tmp/corrupted_wal_backup
|
||||
```
|
||||
```sh
|
||||
cp "$TMHOME/data/cs.wal/wal" > /tmp/corrupted_wal_backup
|
||||
```
|
||||
|
||||
2. Use `./scripts/wal2json` to create a human-readable version
|
||||
2) Use `./scripts/wal2json` to create a human-readable version:
|
||||
|
||||
```
|
||||
./scripts/wal2json/wal2json "$TMHOME/data/cs.wal/wal" > /tmp/corrupted_wal
|
||||
```
|
||||
```sh
|
||||
./scripts/wal2json/wal2json "$TMHOME/data/cs.wal/wal" > /tmp/corrupted_wal
|
||||
```
|
||||
|
||||
3. Search for a "CORRUPTED MESSAGE" line.
|
||||
4. By looking at the previous message and the message after the corrupted one
|
||||
3) Search for a "CORRUPTED MESSAGE" line.
|
||||
4) By looking at the previous message and the message after the corrupted one
|
||||
and looking at the logs, try to rebuild the message. If the consequent
|
||||
messages are marked as corrupted too (this may happen if length header
|
||||
got corrupted or some writes did not make it to the WAL ~ truncation),
|
||||
then remove all the lines starting from the corrupted one and restart
|
||||
Tendermint.
|
||||
|
||||
```
|
||||
$EDITOR /tmp/corrupted_wal
|
||||
```
|
||||
```sh
|
||||
$EDITOR /tmp/corrupted_wal
|
||||
```
|
||||
|
||||
5. After editing, convert this file back into binary form by running:
|
||||
5) After editing, convert this file back into binary form by running:
|
||||
|
||||
```
|
||||
./scripts/json2wal/json2wal /tmp/corrupted_wal $TMHOME/data/cs.wal/wal
|
||||
```
|
||||
```sh
|
||||
./scripts/json2wal/json2wal /tmp/corrupted_wal $TMHOME/data/cs.wal/wal
|
||||
```
|
||||
|
||||
## Hardware
|
||||
|
||||
@@ -313,7 +313,7 @@ If you are going to use Tendermint in a private domain and you have a
|
||||
private high-speed network among your peers, it makes sense to lower
|
||||
flush throttle timeout and increase other params.
|
||||
|
||||
```
|
||||
```toml
|
||||
[p2p]
|
||||
|
||||
send_rate=20000000 # 2MB/s
|
||||
@@ -380,7 +380,7 @@ The process file limits must also be increased, e.g. via `ulimit -n 8192`.
|
||||
|
||||
...for N connections, such as 50k:
|
||||
|
||||
```
|
||||
```md
|
||||
kern.maxfiles=10000+2*N # BSD
|
||||
kern.maxfilesperproc=100+2*N # BSD
|
||||
kern.ipc.maxsockets=10000+2*N # BSD
|
||||
|
||||
@@ -48,43 +48,43 @@ definition](https://github.com/tendermint/tendermint/blob/master/types/genesis.g
|
||||
every blockchain.** If your testnet blockchains do not have unique
|
||||
chain IDs, you will have a bad time. The ChainID must be less than 50 symbols.
|
||||
- `consensus_params` [spec](https://github.com/tendermint/spec/blob/master/spec/core/state.md#consensusparams)
|
||||
- `block`
|
||||
- `max_bytes`: Max block size, in bytes.
|
||||
- `max_gas`: Max gas per block.
|
||||
- `time_iota_ms`: Minimum time increment between consecutive blocks (in
|
||||
- `block`
|
||||
- `max_bytes`: Max block size, in bytes.
|
||||
- `max_gas`: Max gas per block.
|
||||
- `time_iota_ms`: Minimum time increment between consecutive blocks (in
|
||||
milliseconds). If the block header timestamp is ahead of the system clock,
|
||||
decrease this value.
|
||||
- `evidence`
|
||||
- `max_age_num_blocks`: Max age of evidence, in blocks. The basic formula
|
||||
- `evidence`
|
||||
- `max_age_num_blocks`: Max age of evidence, in blocks. The basic formula
|
||||
for calculating this is: MaxAgeDuration / {average block time}.
|
||||
- `max_age_duration`: Max age of evidence, in time. It should correspond
|
||||
- `max_age_duration`: Max age of evidence, in time. It should correspond
|
||||
with an app's "unbonding period" or other similar mechanism for handling
|
||||
[Nothing-At-Stake
|
||||
attacks](https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed).
|
||||
- `max_num`: This sets the maximum number of evidence that can be committed
|
||||
- `max_num`: This sets the maximum number of evidence that can be committed
|
||||
in a single block. and should fall comfortably under the max block
|
||||
bytes when we consider the size of each evidence.
|
||||
- `proof_trial_period`: Proof trial period dictates the time given for
|
||||
- `proof_trial_period`: Proof trial period dictates the time given for
|
||||
nodes accused of amnesia evidence, incorrectly voting twice in two
|
||||
different rounds to respond with their respective proofs.
|
||||
- `validator`
|
||||
- `pub_key_types`: Public key types validators can use.
|
||||
- `version`
|
||||
- `app_version`: ABCI application version.
|
||||
- `validator`
|
||||
- `pub_key_types`: Public key types validators can use.
|
||||
- `version`
|
||||
- `app_version`: ABCI application version.
|
||||
- `validators`: List of initial validators. Note this may be overridden entirely by the
|
||||
application, and may be left empty to make explicit that the
|
||||
application will initialize the validator set with ResponseInitChain.
|
||||
- `pub_key`: The first element specifies the `pub_key` type. 1
|
||||
- `pub_key`: The first element specifies the `pub_key` type. 1
|
||||
== Ed25519. The second element are the pubkey bytes.
|
||||
- `power`: The validator's voting power.
|
||||
- `name`: Name of the validator (optional).
|
||||
- `power`: The validator's voting power.
|
||||
- `name`: Name of the validator (optional).
|
||||
- `app_hash`: The expected application hash (as returned by the
|
||||
`ResponseInfo` ABCI message) upon genesis. If the app's hash does
|
||||
not match, Tendermint will panic.
|
||||
- `app_state`: The application state (e.g. initial distribution
|
||||
of tokens).
|
||||
|
||||
**WARNING: ChainID must be unique to every blockchain. Reusing old chainID can cause issues**
|
||||
> :warning: **ChainID must be unique to every blockchain. Reusing old chainID can cause issues**
|
||||
|
||||
#### Sample genesis.json
|
||||
|
||||
@@ -179,7 +179,7 @@ curl http://localhost:26657/status | json_pp | grep latest_app_hash
|
||||
|
||||
<!-- markdown-link-check-disable -->
|
||||
|
||||
Visit http://localhost:26657 in your browser to see the list of other
|
||||
Visit <http://localhost:26657> 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.
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ The sentry nodes should be able to talk to the entire network hence why `pex=tru
|
||||
|
||||
More Information can be found at these links:
|
||||
|
||||
- https://kb.certus.one/
|
||||
- https://forum.cosmos.network/t/sentry-node-architecture-overview/454
|
||||
- <https://kb.certus.one/>
|
||||
- <https://forum.cosmos.network/t/sentry-node-architecture-overview/454>
|
||||
|
||||
### Validator keys
|
||||
|
||||
@@ -97,7 +97,7 @@ Currently Tendermint uses [Ed25519](https://ed25519.cr.yp.to/) keys which are wi
|
||||
|
||||
## Committing a Block
|
||||
|
||||
_+2/3 is short for "more than 2/3"_
|
||||
> **+2/3 is short for "more than 2/3"**
|
||||
|
||||
A block is committed when +2/3 of the validator set sign [precommit
|
||||
votes](https://github.com/tendermint/spec/blob/953523c3cb99fdb8c8f7a2d21e3a99094279e9de/spec/blockchain/blockchain.md#vote) for that block at the same `round`.
|
||||
|
||||
@@ -16,14 +16,14 @@ Tendermint has some tools that are associated with it for:
|
||||
|
||||
## Benchmarking
|
||||
|
||||
- https://github.com/informalsystems/tm-load-test
|
||||
- <https://github.com/informalsystems/tm-load-test>
|
||||
|
||||
`tm-load-test` is a distributed load testing tool (and framework) for load
|
||||
testing Tendermint networks.
|
||||
|
||||
## Testnets
|
||||
|
||||
- https://github.com/informalsystems/testnets
|
||||
- <https://github.com/informalsystems/testnets>
|
||||
|
||||
This repository contains various different configurations of test networks for,
|
||||
and relating to, Tendermint.
|
||||
|
||||
@@ -16,7 +16,7 @@ tendermint debug kill <pid> </path/to/out.zip> --home=</path/to/app.d>
|
||||
will write debug info into a compressed archive. The archive will contain the
|
||||
following:
|
||||
|
||||
```
|
||||
```sh
|
||||
├── config.toml
|
||||
├── consensus_state.json
|
||||
├── net_info.json
|
||||
@@ -29,7 +29,7 @@ Under the hood, `debug kill` fetches info from `/status`, `/net_info`, and
|
||||
`/dump_consensus_state` HTTP endpoints, and kills the process with `-6`, which
|
||||
catches the go-routine dump.
|
||||
|
||||
## tendermint debug dump
|
||||
## Tendermint debug dump
|
||||
|
||||
Also, the `debug dump` sub-command allows you to dump debugging data into
|
||||
compressed archives at a regular interval. These archives contain the goroutine
|
||||
@@ -44,7 +44,7 @@ will perform similarly to `kill` except it only polls the node and
|
||||
dumps debugging data every frequency seconds to a compressed archive under a
|
||||
given destination directory. Each archive will contain:
|
||||
|
||||
```
|
||||
```sh
|
||||
├── consensus_state.json
|
||||
├── goroutine.out
|
||||
├── heap.out
|
||||
|
||||
@@ -21,10 +21,12 @@ When executed, `tm-signer-harness`:
|
||||
error.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Requires the same prerequisites as for building
|
||||
[Tendermint](https://github.com/tendermint/tendermint).
|
||||
|
||||
## Building
|
||||
|
||||
From the `tools/tm-signer-harness` directory in your Tendermint source
|
||||
repository, simply run:
|
||||
|
||||
@@ -36,6 +38,7 @@ make install
|
||||
```
|
||||
|
||||
## Docker Image
|
||||
|
||||
To build a Docker image containing the `tm-signer-harness`, also from the
|
||||
`tools/tm-signer-harness` directory of your Tendermint source repo, simply run:
|
||||
|
||||
@@ -44,6 +47,7 @@ make docker-image
|
||||
```
|
||||
|
||||
## Running against KMS
|
||||
|
||||
As an example of how to use `tm-signer-harness`, the following instructions show
|
||||
you how to execute its tests against [KMS](https://github.com/tendermint/kms).
|
||||
For this example, we will make use of the **software signing module in KMS**, as
|
||||
@@ -51,6 +55,7 @@ the hardware signing module requires a physical
|
||||
[YubiHSM](https://www.yubico.com/products/yubihsm/) device.
|
||||
|
||||
### Step 1: Install KMS on your local machine
|
||||
|
||||
See the [KMS repo](https://github.com/tendermint/kms) for details on how to set
|
||||
KMS up on your local machine.
|
||||
|
||||
@@ -62,6 +67,7 @@ cargo install tmkms
|
||||
```
|
||||
|
||||
### Step 2: Make keys for KMS
|
||||
|
||||
The KMS software signing module needs a key with which to sign messages. In our
|
||||
example, we will simply export a signing key from our local Tendermint instance.
|
||||
|
||||
@@ -85,6 +91,7 @@ tmkms keygen secret_connection.key
|
||||
```
|
||||
|
||||
### Step 3: Configure and run KMS
|
||||
|
||||
KMS needs some configuration to tell it to use the softer signing module as well
|
||||
as the `signing.key` file we just generated. Save the following to a file called
|
||||
`tmkms.toml`:
|
||||
@@ -111,6 +118,7 @@ This will start KMS, which will repeatedly try to connect to
|
||||
`tcp://127.0.0.1:61219` until it is successful.
|
||||
|
||||
### Step 4: Run tm-signer-harness
|
||||
|
||||
Now we get to run the signer test harness:
|
||||
|
||||
```bash
|
||||
@@ -124,10 +132,12 @@ should now exit with a 0 exit code. If they are somehow not compatible, it
|
||||
should exit with a meaningful non-zero exit code (see the exit codes below).
|
||||
|
||||
### Step 5: Shut down KMS
|
||||
|
||||
Simply hit Ctrl+Break on your KMS instance (or use the `kill` command in Linux)
|
||||
to terminate it gracefully.
|
||||
|
||||
## Exit Code Meanings
|
||||
|
||||
The following list shows the various exit codes from `tm-signer-harness` and
|
||||
their meanings:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user