Merge pull request #1903 from tendermint/zach/lint-md
lint the docs markdown & fix codeblocks for website
This commit is contained in:
commit
82a5e9604c
|
@ -10,17 +10,22 @@ Make sure you [have Go installed](https://golang.org/doc/install).
|
|||
|
||||
Next, install the `abci-cli` tool and example applications:
|
||||
|
||||
```
|
||||
go get github.com/tendermint/tendermint
|
||||
```
|
||||
|
||||
to get vendored dependencies:
|
||||
|
||||
```
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
make get_tools
|
||||
make get_vendor_deps
|
||||
make install_abci
|
||||
```
|
||||
|
||||
Now run `abci-cli` to see the list of commands:
|
||||
|
||||
```
|
||||
Usage:
|
||||
abci-cli [command]
|
||||
|
||||
|
@ -45,6 +50,7 @@ Now run `abci-cli` to see the list of commands:
|
|||
-v, --verbose print the command and results as if it were a console session
|
||||
|
||||
Use "abci-cli [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
## KVStore - First Example
|
||||
|
||||
|
@ -63,6 +69,7 @@ Its code can be found
|
|||
[here](https://github.com/tendermint/tendermint/blob/develop/abci/cmd/abci-cli/abci-cli.go)
|
||||
and looks like:
|
||||
|
||||
```
|
||||
func cmdKVStore(cmd *cobra.Command, args []string) error {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
|
||||
|
@ -92,25 +99,34 @@ and looks like:
|
|||
})
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Start by running:
|
||||
|
||||
```
|
||||
abci-cli kvstore
|
||||
```
|
||||
|
||||
And in another terminal, run
|
||||
|
||||
```
|
||||
abci-cli echo hello
|
||||
abci-cli info
|
||||
```
|
||||
|
||||
You'll see something like:
|
||||
|
||||
```
|
||||
-> data: hello
|
||||
-> data.hex: 68656C6C6F
|
||||
```
|
||||
|
||||
and:
|
||||
|
||||
```
|
||||
-> data: {"size":0}
|
||||
-> data.hex: 7B2273697A65223A307D
|
||||
```
|
||||
|
||||
An ABCI application must provide two things:
|
||||
|
||||
|
@ -144,6 +160,7 @@ speaking ABCI messages to your application.
|
|||
|
||||
Try running these commands:
|
||||
|
||||
```
|
||||
> echo hello
|
||||
-> code: OK
|
||||
-> data: hello
|
||||
|
@ -190,6 +207,7 @@ Try running these commands:
|
|||
-> height: 0
|
||||
-> value: xyz
|
||||
-> value.hex: 78797A
|
||||
```
|
||||
|
||||
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)`.
|
||||
|
@ -206,6 +224,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:
|
||||
|
||||
```
|
||||
func cmdCounter(cmd *cobra.Command, args []string) error {
|
||||
|
||||
app := counter.NewCounterApplication(flagSerial)
|
||||
|
@ -229,6 +248,7 @@ and looks like:
|
|||
})
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
|
@ -256,10 +276,13 @@ whose integer is greater than the last committed one.
|
|||
Let's kill the console and the kvstore application, and start the
|
||||
counter app:
|
||||
|
||||
```
|
||||
abci-cli counter
|
||||
```
|
||||
|
||||
In another window, start the `abci-cli console`:
|
||||
|
||||
```
|
||||
> set_option serial on
|
||||
-> code: OK
|
||||
-> log: OK (SetOption doesn't return anything.)
|
||||
|
@ -288,6 +311,7 @@ In another window, start the `abci-cli console`:
|
|||
-> code: OK
|
||||
-> data: {"hashes":0,"txs":2}
|
||||
-> data.hex: 0x7B22686173686573223A302C22747873223A327D
|
||||
```
|
||||
|
||||
This is a very simple application, but between `counter` and `kvstore`,
|
||||
its easy to see how you can build out arbitrary application states on
|
||||
|
@ -304,7 +328,9 @@ example directory](https://github.com/tendermint/tendermint/tree/develop/abci/ex
|
|||
|
||||
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
|
||||
|
|
|
@ -17,7 +17,7 @@ transaction is actually processed.
|
|||
|
||||
The ABCI application must be a deterministic result of the Tendermint
|
||||
consensus - any external influence on the application state that didn't
|
||||
come through Tendermint could cause a consensus failure. Thus *nothing*
|
||||
come through Tendermint could cause a consensus failure. Thus _nothing_
|
||||
should communicate with the application except Tendermint via ABCI.
|
||||
|
||||
If the application is written in Go, it can be compiled into the
|
||||
|
@ -43,6 +43,7 @@ all transactions, and possibly all queries, should still pass through
|
|||
Tendermint.
|
||||
|
||||
See the following for more extensive documentation:
|
||||
|
||||
- [Interchain Standard for the Light-Client REST API](https://github.com/cosmos/cosmos-sdk/pull/1028)
|
||||
- [Tendermint RPC Docs](https://tendermint.github.io/slate/)
|
||||
- [Tendermint in Production](https://github.com/tendermint/tendermint/pull/1618)
|
||||
|
|
|
@ -34,8 +34,7 @@ The ABCI design has a few distinct components:
|
|||
only uses `CheckTx`
|
||||
- [consensus connection](#consensus-connection): for executing
|
||||
transactions that have been committed. Message sequence is
|
||||
-for every block
|
||||
-`BeginBlock, [DeliverTx, ...], EndBlock, Commit`
|
||||
-for every block -`BeginBlock, [DeliverTx, ...], EndBlock, Commit`
|
||||
- [query connection](#query-connection): for querying the
|
||||
application state; only uses Query and Info
|
||||
|
||||
|
@ -161,7 +160,7 @@ connection, to query the local state of the app.
|
|||
|
||||
### Mempool Connection
|
||||
|
||||
The mempool connection is used *only* for CheckTx requests. Transactions
|
||||
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.
|
||||
|
@ -180,12 +179,15 @@ mempool state (this behaviour can be turned off with
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) CheckTx(tx []byte) types.Result {
|
||||
return types.OK
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
ResponseCheckTx requestCheckTx(RequestCheckTx req) {
|
||||
byte[] transaction = req.getTx().toByteArray();
|
||||
|
||||
|
@ -197,6 +199,7 @@ In Java:
|
|||
return ResponseCheckTx.newBuilder().setCode(CodeType.OK).build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Replay Protection
|
||||
|
||||
|
@ -242,6 +245,7 @@ merkle root of the data returned by the DeliverTx requests, or both.
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
// tx is either "key=value" or just arbitrary bytes
|
||||
func (app *KVStoreApplication) DeliverTx(tx []byte) types.Result {
|
||||
parts := strings.Split(string(tx), "=")
|
||||
|
@ -252,9 +256,11 @@ In go:
|
|||
}
|
||||
return types.OK
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
/**
|
||||
* Using Protobuf types from the protoc compiler, we always start with a byte[]
|
||||
*/
|
||||
|
@ -270,6 +276,7 @@ In Java:
|
|||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Commit
|
||||
|
||||
|
@ -277,8 +284,8 @@ 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
|
||||
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.
|
||||
|
@ -294,13 +301,16 @@ job of the [Handshake](#handshake).
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) Commit() types.Result {
|
||||
hash := app.state.Hash()
|
||||
return types.NewResultOK(hash, "")
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
ResponseCommit requestCommit(RequestCommit requestCommit) {
|
||||
|
||||
// update the internal app-state
|
||||
|
@ -309,6 +319,7 @@ In Java:
|
|||
// and return it to the node
|
||||
return ResponseCommit.newBuilder().setCode(CodeType.OK).setData(ByteString.copyFrom(newAppState)).build();
|
||||
}
|
||||
```
|
||||
|
||||
### BeginBlock
|
||||
|
||||
|
@ -322,6 +333,7 @@ pick up from when it restarts. See information on the Handshake, below.
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
// Track the block hash and header information
|
||||
func (app *PersistentKVStoreApplication) BeginBlock(params types.RequestBeginBlock) {
|
||||
// update latest block info
|
||||
|
@ -330,9 +342,11 @@ In go:
|
|||
// reset valset changes
|
||||
app.changes = make([]*types.Validator, 0)
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
/*
|
||||
* all types come from protobuf definition
|
||||
*/
|
||||
|
@ -347,6 +361,7 @@ In Java:
|
|||
|
||||
return ResponseBeginBlock.newBuilder().build();
|
||||
}
|
||||
```
|
||||
|
||||
### EndBlock
|
||||
|
||||
|
@ -364,13 +379,16 @@ for details on how it tracks validators.
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
// Update the validator set
|
||||
func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock {
|
||||
return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
/*
|
||||
* Assume that one validator changes. The new validator has a power of 10
|
||||
*/
|
||||
|
@ -383,6 +401,7 @@ In Java:
|
|||
|
||||
return builder.build();
|
||||
}
|
||||
```
|
||||
|
||||
### Query Connection
|
||||
|
||||
|
@ -406,6 +425,7 @@ Note: these query formats are subject to change!
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
if reqQuery.Prove {
|
||||
value, proof, exists := app.state.Proof(reqQuery.Data)
|
||||
|
@ -431,9 +451,11 @@ In go:
|
|||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
ResponseQuery requestQuery(RequestQuery req) {
|
||||
final boolean isProveQuery = req.getProve();
|
||||
final ResponseQuery.Builder responseBuilder = ResponseQuery.newBuilder();
|
||||
|
@ -458,6 +480,7 @@ In Java:
|
|||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
```
|
||||
|
||||
### Handshake
|
||||
|
||||
|
@ -477,17 +500,21 @@ all blocks.
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
||||
return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
ResponseInfo requestInfo(RequestInfo req) {
|
||||
final byte[] lastAppHash = getLastAppHash();
|
||||
final long lastHeight = getLastHeight();
|
||||
return ResponseInfo.newBuilder().setLastBlockAppHash(ByteString.copyFrom(lastAppHash)).setLastBlockHeight(lastHeight).build();
|
||||
}
|
||||
```
|
||||
|
||||
### Genesis
|
||||
|
||||
|
@ -497,6 +524,7 @@ consensus params.
|
|||
|
||||
In go:
|
||||
|
||||
```
|
||||
// Save the validators in the merkle tree
|
||||
func (app *PersistentKVStoreApplication) InitChain(params types.RequestInitChain) {
|
||||
for _, v := range params.Validators {
|
||||
|
@ -506,9 +534,11 @@ In go:
|
|||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In Java:
|
||||
|
||||
```
|
||||
/*
|
||||
* all types come from protobuf definition
|
||||
*/
|
||||
|
@ -525,3 +555,4 @@ In Java:
|
|||
|
||||
return ResponseInitChain.newBuilder().build();
|
||||
}
|
||||
```
|
||||
|
|
|
@ -16,30 +16,29 @@ 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 and a node key for each validator using
|
||||
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 and a node key for each validator using
|
||||
`tendermint init`
|
||||
4) Compile a list of public keys for each validator into a
|
||||
4. Compile a list of public keys for each validator into a
|
||||
`genesis.json` file and replace the existing file with it.
|
||||
5) Run
|
||||
`tendermint node --proxy_app=kvstore --p2p.persistent_peers=< peer
|
||||
addresses >` on each node, where `< peer addresses >` is a comma separated
|
||||
5. Run
|
||||
`tendermint node --proxy_app=kvstore --p2p.persistent_peers=< peer addresses >` on each node, where `< peer addresses >` is a comma separated
|
||||
list of the ID@IP:PORT combination for each node. The default port for
|
||||
Tendermint is `26656`. The ID of a node can be obtained by running
|
||||
`tendermint show_node_id` command. 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 --proxy_app=kvstore --p2p.persistent_peers=96663a3dd0d7b9d17d4c8211b191af259621c693@192.168.0.1:26656, 429fcf25974313b95673f58d77eacdd434402665@192.168.0.2:26656, 0491d373a8e0fcf1023aaf18c51d6a1d0d4f31bd@192.168.0.3:26656, f9baeaa15fedf5e1ef7448dd60f46c01f1a9e9c4@192.168.0.4:26656
|
||||
```
|
||||
|
||||
After a few seconds, all the nodes should connect to each other and
|
||||
start making blocks! For more information, see the Tendermint Networks
|
||||
section of [the guide to using Tendermint](./using-tendermint.md).
|
||||
|
||||
But wait! Steps 3, 4 and 5 are quite manual. Instead, use the `tendermint
|
||||
testnet` command. By default, running `tendermint testnet` will create all the
|
||||
But wait! Steps 3, 4 and 5 are quite manual. Instead, use the `tendermint testnet` command. By default, running `tendermint testnet` will create all the
|
||||
required files, but it won't populate the list of persistent peers. It will do
|
||||
it however if you provide the `--populate-persistent-peers` flag and optional
|
||||
`--starting-ip-address` flag. Run `tendermint testnet --help` for more details
|
||||
|
@ -63,7 +62,9 @@ The easiest and fastest way to get a testnet up in less than 5 minutes.
|
|||
|
||||
With `docker` and `docker-compose` installed, run the command:
|
||||
|
||||
```
|
||||
make localnet-start
|
||||
```
|
||||
|
||||
from the root of the tendermint repository. This will spin up a 4-node
|
||||
local testnet. Review the target in the Makefile to debug any problems.
|
||||
|
|
|
@ -24,6 +24,7 @@ The script is also used to facilitate cluster deployment below.
|
|||
### Manual Install
|
||||
|
||||
Requires:
|
||||
|
||||
- `go` minimum version 1.10
|
||||
- `$GOPATH` environment variable must be set
|
||||
- `$GOPATH/bin` must be on your `$PATH` (see https://github.com/tendermint/tendermint/wiki/Setting-GOPATH)
|
||||
|
|
|
@ -25,11 +25,13 @@ more info.
|
|||
|
||||
Then run
|
||||
|
||||
```
|
||||
go get github.com/tendermint/tendermint
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
make get_tools
|
||||
make get_vendor_deps
|
||||
make install_abci
|
||||
```
|
||||
|
||||
Now you should have the `abci-cli` installed; you'll see a couple of
|
||||
commands (`counter` and `kvstore`) that are example applications written
|
||||
|
@ -47,13 +49,17 @@ full transaction bytes are stored as the key and the value.
|
|||
|
||||
Let's start a kvstore application.
|
||||
|
||||
```
|
||||
abci-cli kvstore
|
||||
```
|
||||
|
||||
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
|
||||
|
@ -63,14 +69,18 @@ details, see [the guide on using Tendermint](./using-tendermint.md).
|
|||
You should see Tendermint making blocks! We can get the status of our
|
||||
Tendermint node as follows:
|
||||
|
||||
```
|
||||
curl -s localhost:26657/status
|
||||
```
|
||||
|
||||
The `-s` just silences `curl`. For nicer output, pipe the result into a
|
||||
tool like [jq](https://stedolan.github.io/jq/) or `json_pp`.
|
||||
|
||||
Now let's send some transactions to the kvstore.
|
||||
|
||||
```
|
||||
curl -s 'localhost:26657/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
|
||||
|
@ -78,6 +88,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:
|
||||
|
||||
```
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
|
@ -102,14 +113,18 @@ like:
|
|||
"height": 14
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can confirm that our transaction worked and the value got stored by
|
||||
querying the app:
|
||||
|
||||
```
|
||||
curl -s 'localhost:26657/abci_query?data="abcd"'
|
||||
```
|
||||
|
||||
The result should look like:
|
||||
|
||||
```
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
|
@ -122,6 +137,7 @@ The result should look like:
|
|||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note the `value` in the result (`YWJjZA==`); this is the base64-encoding
|
||||
of the ASCII of `abcd`. You can verify this in a python 2 shell by
|
||||
|
@ -132,12 +148,16 @@ human-readable](https://github.com/tendermint/tendermint/issues/1794).
|
|||
|
||||
Now let's try setting a different key and value:
|
||||
|
||||
```
|
||||
curl -s 'localhost:26657/broadcast_tx_commit?tx="name=satoshi"'
|
||||
```
|
||||
|
||||
Now if we query for `name`, we should get `satoshi`, or `c2F0b3NoaQ==`
|
||||
in base64:
|
||||
|
||||
```
|
||||
curl -s 'localhost:26657/abci_query?data="name"'
|
||||
```
|
||||
|
||||
Try some other transactions and queries to make sure everything is
|
||||
working!
|
||||
|
@ -171,22 +191,29 @@ 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:
|
||||
|
||||
```
|
||||
abci-cli 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: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:
|
||||
|
||||
```
|
||||
> curl localhost:26657/broadcast_tx_commit?tx=0x05
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
|
@ -204,9 +231,11 @@ the number `1`. If instead, we try to send a `5`, we get an error:
|
|||
"height": 34
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
But if we send a `1`, it works again:
|
||||
|
||||
```
|
||||
> curl localhost:26657/broadcast_tx_commit?tx=0x01
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
|
@ -222,6 +251,7 @@ But if we send a `1`, it works again:
|
|||
"height": 60
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more details on the `broadcast_tx` API, see [the guide on using
|
||||
Tendermint](./using-tendermint.md).
|
||||
|
@ -236,26 +266,34 @@ 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
|
||||
cd ..
|
||||
```
|
||||
|
||||
Kill the previous `counter` and `tendermint` processes. Now run the app:
|
||||
|
||||
```
|
||||
node example/counter.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:26657/broadcast_tx_commit?tx=0x00 # ok
|
||||
curl localhost:26657/broadcast_tx_commit?tx=0x05 # invalid nonce
|
||||
curl localhost:26657/broadcast_tx_commit?tx=0x01 # ok
|
||||
```
|
||||
|
||||
Neat, eh?
|
||||
|
|
|
@ -5,20 +5,25 @@
|
|||
We first create three connections (mempool, consensus and query) to the
|
||||
application (running `kvstore` locally in this case).
|
||||
|
||||
```
|
||||
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
|
||||
I[10-04|13:54:27.367] Starting localClient module=abci-client connection=consensus impl=localClient
|
||||
```
|
||||
|
||||
Then Tendermint Core and the application perform a handshake.
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
After that, we start a few more things like the event switch, reactors,
|
||||
and perform UPNP discover in order to detect the IP address.
|
||||
|
||||
```
|
||||
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
|
||||
|
@ -34,20 +39,25 @@ and perform UPNP discover in order to detect the IP address.
|
|||
I[10-04|13:54:30.387] Starting ConsensusState module=consensus impl=ConsensusState
|
||||
I[10-04|13:54:30.387] Starting WAL module=consensus wal=/home/vagrant/.tendermint/data/cs.wal/wal impl=WAL
|
||||
I[10-04|13:54:30.388] Starting TimeoutTicker module=consensus impl=TimeoutTicker
|
||||
```
|
||||
|
||||
Notice the second row where Tendermint Core reports that "This node is a
|
||||
validator". It also could be just an observer (regular node).
|
||||
|
||||
Next we replay all the messages from the WAL.
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
"Started node" message signals that everything is ready for work.
|
||||
|
||||
```
|
||||
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])}"
|
||||
```
|
||||
|
||||
Next follows a standard block creation cycle, where we enter a new
|
||||
round, propose a block, receive more than 2/3 of prevotes, then
|
||||
|
@ -56,6 +66,7 @@ please refer to [Consensus
|
|||
Overview](./introduction.md#consensus-overview) or [Byzantine Consensus
|
||||
Algorithm](./spec/consensus).
|
||||
|
||||
```
|
||||
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}"
|
||||
|
@ -94,6 +105,7 @@ Algorithm](./spec/consensus).
|
|||
I[10-04|13:54:30.408] Executed block module=state height=91 validTxs=0 invalidTxs=0
|
||||
I[10-04|13:54:30.410] Committed state module=state height=91 txs=0 hash=E0FBAFBF6FCED8B9786DDFEB1A0D4FA2501BADAD
|
||||
I[10-04|13:54:30.410] Recheck txs module=mempool numtxs=0 height=91
|
||||
```
|
||||
|
||||
## List of modules
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ to their results.
|
|||
|
||||
Let's take a look at the `[tx_index]` config section:
|
||||
|
||||
```
|
||||
##### transactions indexer configuration options #####
|
||||
[tx_index]
|
||||
|
||||
|
@ -26,6 +27,7 @@ Let's take a look at the `[tx_index]` config section:
|
|||
# desirable (see the comment above). IndexTags has a precedence over
|
||||
# IndexAllTags (i.e. when given both, IndexTags will be indexed).
|
||||
index_all_tags = false
|
||||
```
|
||||
|
||||
By default, Tendermint will index all transactions by their respective
|
||||
hashes using an embedded simple indexer. Note, we are planning to add
|
||||
|
@ -39,6 +41,7 @@ pairs of UTF-8 encoded strings (e.g. "account.owner": "Bob", "balance":
|
|||
|
||||
Example:
|
||||
|
||||
```
|
||||
func (app *KVStoreApplication) DeliverTx(tx []byte) types.Result {
|
||||
...
|
||||
tags := []cmn.KVPair{
|
||||
|
@ -48,6 +51,7 @@ Example:
|
|||
}
|
||||
return types.ResponseDeliverTx{Code: code.CodeTypeOK, Tags: tags}
|
||||
}
|
||||
```
|
||||
|
||||
If you want Tendermint to only index transactions by "account.name" tag,
|
||||
in the config set `tx_index.index_tags="account.name"`. If you to index
|
||||
|
@ -66,7 +70,9 @@ Tendermint will throw a warning if you try to use any of the above keys.
|
|||
You can query the transaction results by calling `/tx_search` RPC
|
||||
endpoint:
|
||||
|
||||
```
|
||||
curl "localhost:26657/tx_search?query=\"account.name='igor'\"&prove=true"
|
||||
```
|
||||
|
||||
Check out [API docs](https://tendermint.github.io/slate/?shell#txsearch)
|
||||
for more information on query syntax and other options.
|
||||
|
@ -76,6 +82,7 @@ for more information on query syntax and other options.
|
|||
Clients can subscribe to transactions with the given tags via Websocket
|
||||
by providing a query to `/subscribe` RPC endpoint.
|
||||
|
||||
```
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "subscribe",
|
||||
|
@ -84,6 +91,7 @@ by providing a query to `/subscribe` RPC endpoint.
|
|||
"query": "account.name='igor'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Check out [API docs](https://tendermint.github.io/slate/#subscribe) for
|
||||
more information on query syntax and other options.
|
||||
|
|
|
@ -61,6 +61,7 @@ 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
|
||||
|
@ -298,8 +299,8 @@ 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
|
||||
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
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"prettier": "^1.13.7",
|
||||
"remark-cli": "^5.0.0",
|
||||
"remark-lint-no-dead-urls": "^0.3.0",
|
||||
"textlint": "^10.2.1"
|
||||
},
|
||||
"name": "tendermint",
|
||||
"description": "Tendermint Core Documentation",
|
||||
"version": "0.0.1",
|
||||
"main": "README.md",
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"lint:json": "prettier \"**/*.json\" --write",
|
||||
"lint:md": "prettier \"**/*.md\" --write && remark . && textlint \"md/**\"",
|
||||
"lint": "yarn lint:json && yarn lint:md"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tendermint/tendermint.git"
|
||||
},
|
||||
"keywords": [
|
||||
"tendermint",
|
||||
"blockchain"
|
||||
],
|
||||
"author": "Tendermint",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/tendermint/tendermint/issues"
|
||||
},
|
||||
"homepage": "https://tendermint.com/docs/",
|
||||
"remarkConfig": {
|
||||
"plugins": [
|
||||
"remark-lint-no-dead-urls"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -49,14 +49,18 @@ second TODO is to query the /status RPC endpoint. It provides the
|
|||
necessary info: whenever the node is syncing or not, what height it is
|
||||
on, etc.
|
||||
|
||||
$ curl http(s)://{ip}:{rpcPort}/status
|
||||
```
|
||||
curl http(s)://{ip}:{rpcPort}/status
|
||||
```
|
||||
|
||||
`dump_consensus_state` will give you a detailed overview of the
|
||||
consensus state (proposer, lastest validators, peers states). From it,
|
||||
you should be able to figure out why, for example, the network had
|
||||
halted.
|
||||
|
||||
$ curl http(s)://{ip}:{rpcPort}/dump_consensus_state
|
||||
```
|
||||
curl http(s)://{ip}:{rpcPort}/dump_consensus_state
|
||||
```
|
||||
|
||||
There is a reduced version of this endpoint - `consensus_state`, which
|
||||
returns just the votes seen at the current height.
|
||||
|
@ -152,12 +156,14 @@ 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.
|
||||
|
||||
```
|
||||
[p2p]
|
||||
|
||||
send_rate=20000000 # 2MB/s
|
||||
recv_rate=20000000 # 2MB/s
|
||||
flush_throttle_timeout=10
|
||||
max_packet_msg_payload_size=10240 # 10KB
|
||||
```
|
||||
|
||||
- `mempool.recheck`
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
Tendermint Core can be configured via a TOML file in
|
||||
`$TMHOME/config/config.toml`. Some of these parameters can be overridden by
|
||||
command-line flags. For most users, the options in the `##### main
|
||||
base configuration options #####` are intended to be modified while
|
||||
command-line flags. For most users, the options in the `##### main base configuration options #####` are intended to be modified while
|
||||
config options further below are intended for advance power users.
|
||||
|
||||
## Options
|
||||
|
|
|
@ -9,6 +9,7 @@ for third-party applications (for analysys) or inspecting state.
|
|||
You can subscribe to any of the events above by calling `subscribe` RPC
|
||||
method via Websocket.
|
||||
|
||||
```
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "subscribe",
|
||||
|
@ -17,6 +18,7 @@ method via Websocket.
|
|||
"query": "tm.event='NewBlock'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Check out [API docs](https://tendermint.github.io/slate/#subscribe) for
|
||||
more information on query syntax and other options.
|
||||
|
|
|
@ -44,6 +44,7 @@ then:
|
|||
terraform init
|
||||
terraform apply -var DO_API_TOKEN="$DO_API_TOKEN" -var SSH_KEY_FILE="$SSH_KEY_FILE"
|
||||
```
|
||||
|
||||
and you will get a list of IP addresses that belong to your droplets.
|
||||
|
||||
With the droplets created and running, let's setup Ansible.
|
||||
|
|
|
@ -16,7 +16,9 @@ this by setting the `TMHOME` environment variable.
|
|||
|
||||
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, in
|
||||
|
@ -25,24 +27,30 @@ with one validator.
|
|||
|
||||
For more elaborate initialization, see the tesnet command:
|
||||
|
||||
```
|
||||
tendermint testnet --help
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
To run a Tendermint node, use
|
||||
|
||||
```
|
||||
tendermint node
|
||||
```
|
||||
|
||||
By default, Tendermint will try to connect to an ABCI application on
|
||||
[127.0.0.1:26658](127.0.0.1:26658). If you have the `kvstore` ABCI app
|
||||
installed, run it in another window. If you don't, kill Tendermint and
|
||||
run an in-process version of the `kvstore` app:
|
||||
|
||||
```
|
||||
tendermint node --proxy_app=kvstore
|
||||
```
|
||||
|
||||
After a few seconds you should see blocks start streaming in. Note that
|
||||
blocks are produced regularly, even if there are no transactions. See
|
||||
*No Empty Blocks*, below, to modify this setting.
|
||||
_No Empty Blocks_, below, to modify this setting.
|
||||
|
||||
Tendermint supports in-process versions of the `counter`, `kvstore` and
|
||||
`nil` apps that ship as examples with `abci-cli`. It's easy to compile
|
||||
|
@ -51,22 +59,30 @@ 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, for example:
|
||||
|
||||
```
|
||||
curl http://localhost:26657/broadcast_tx_commit?tx=\"abcd\"
|
||||
```
|
||||
|
||||
We can see the chain's status at the `/status` end-point:
|
||||
|
||||
```
|
||||
curl http://localhost:26657/status | json_pp
|
||||
```
|
||||
|
||||
and the `latest_app_hash` in particular:
|
||||
|
||||
```
|
||||
curl http://localhost:26657/status | json_pp | grep latest_app_hash
|
||||
```
|
||||
|
||||
Visit http://localhost:26657> in your browser to see the list of other
|
||||
endpoints. Some take no arguments (like `/status`), while others specify
|
||||
|
@ -81,30 +97,40 @@ With `GET`:
|
|||
|
||||
To send a UTF8 string byte array, quote the value of the tx pramater:
|
||||
|
||||
```
|
||||
curl 'http://localhost:26657/broadcast_tx_commit?tx="hello"'
|
||||
```
|
||||
|
||||
which sends a 5 byte transaction: "h e l l o" \[68 65 6c 6c 6f\].
|
||||
|
||||
Note the URL must be wrapped with single quoes, else bash will ignore
|
||||
the double quotes. To avoid the single quotes, escape the double quotes:
|
||||
|
||||
```
|
||||
curl http://localhost:26657/broadcast_tx_commit?tx=\"hello\"
|
||||
```
|
||||
|
||||
Using a special character:
|
||||
|
||||
```
|
||||
curl 'http://localhost:26657/broadcast_tx_commit?tx="€5"'
|
||||
```
|
||||
|
||||
sends a 4 byte transaction: "€5" (UTF8) \[e2 82 ac 35\].
|
||||
|
||||
To send as raw hex, omit quotes AND prefix the hex string with `0x`:
|
||||
|
||||
```
|
||||
curl http://localhost:26657/broadcast_tx_commit?tx=0x01020304
|
||||
```
|
||||
|
||||
which sends a 4 byte transaction: \[01 02 03 04\].
|
||||
|
||||
With `POST` (using `json`), the raw hex must be `base64` encoded:
|
||||
|
||||
```
|
||||
curl --data-binary '{"jsonrpc":"2.0","id":"anything","method":"broadcast_tx_commit","params": {"tx": "AQIDBA=="}}' -H 'content-type:text/plain;' http://localhost:26657
|
||||
```
|
||||
|
||||
which sends the same 4 byte transaction: \[01 02 03 04\].
|
||||
|
||||
|
@ -118,7 +144,9 @@ 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
|
||||
|
@ -150,21 +178,27 @@ To configure Tendermint to not produce empty blocks unless there are
|
|||
transactions or the app hash changes, run Tendermint with this
|
||||
additional flag:
|
||||
|
||||
```
|
||||
tendermint node --consensus.create_empty_blocks=false
|
||||
```
|
||||
|
||||
or set the configuration via the `config.toml` file:
|
||||
|
||||
```
|
||||
[consensus]
|
||||
create_empty_blocks = false
|
||||
```
|
||||
|
||||
Remember: because the default is to *create empty blocks*, avoiding
|
||||
Remember: because the default is to _create empty blocks_, avoiding
|
||||
empty blocks requires the config option to be set to `false`.
|
||||
|
||||
The block interval setting allows for a delay (in seconds) between the
|
||||
creation of each new empty block. It is set via the `config.toml`:
|
||||
|
||||
```
|
||||
[consensus]
|
||||
create_empty_blocks_interval = 5
|
||||
```
|
||||
|
||||
With this setting, empty blocks will be produced every 5s if no block
|
||||
has been produced otherwise, regardless of the value of
|
||||
|
@ -181,9 +215,11 @@ 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`,
|
||||
|
@ -208,6 +244,7 @@ When `tendermint init` is run, both a `genesis.json` and
|
|||
`priv_validator.json` are created in `~/.tendermint/config`. The
|
||||
`genesis.json` might look like:
|
||||
|
||||
```
|
||||
{
|
||||
"validators" : [
|
||||
{
|
||||
|
@ -223,9 +260,11 @@ When `tendermint init` is run, both a `genesis.json` and
|
|||
"chain_id" : "test-chain-rDlYSN",
|
||||
"genesis_time" : "0001-01-01T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
And the `priv_validator.json`:
|
||||
|
||||
```
|
||||
{
|
||||
"last_step" : 0,
|
||||
"last_round" : "0",
|
||||
|
@ -240,6 +279,7 @@ And the `priv_validator.json`:
|
|||
"type" : "tendermint/PrivKeyEd25519"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `priv_validator.json` actually contains a private key, and should
|
||||
thus be kept absolutely secret; for now we work with the plain text.
|
||||
|
@ -272,6 +312,7 @@ with the consensus protocol.
|
|||
### Peers
|
||||
|
||||
#### Seed
|
||||
|
||||
A seed node is a node who relays the addresses of other peers which they know
|
||||
of. These nodes constantly crawl the network to try to get more peers. The
|
||||
addresses which the seed node relays get saved into a local address book. Once
|
||||
|
@ -282,6 +323,7 @@ only need them on the first start. The seed node will immediately disconnect
|
|||
from you after sending you some addresses.
|
||||
|
||||
#### Persistent Peer
|
||||
|
||||
Persistent peers are people you want to be constantly connected with. If you
|
||||
disconnect you will try to connect directly back to them as opposed to using
|
||||
another address from the address book. On restarts you will always try to
|
||||
|
@ -302,12 +344,16 @@ persistent connections with.
|
|||
|
||||
For example,
|
||||
|
||||
```
|
||||
tendermint node --p2p.seeds "f9baeaa15fedf5e1ef7448dd60f46c01f1a9e9c4@1.2.3.4:26656,0491d373a8e0fcf1023aaf18c51d6a1d0d4f31bd@5.6.7.8:26656"
|
||||
```
|
||||
|
||||
Alternatively, you can use the `/dial_seeds` endpoint of the RPC to
|
||||
specify seeds for a running node to connect to:
|
||||
|
||||
```
|
||||
curl 'localhost:26657/dial_seeds?seeds=\["f9baeaa15fedf5e1ef7448dd60f46c01f1a9e9c4@1.2.3.4:26656","0491d373a8e0fcf1023aaf18c51d6a1d0d4f31bd@5.6.7.8:26656"\]'
|
||||
```
|
||||
|
||||
Note, with PeX enabled, you
|
||||
should not need seeds after the first start.
|
||||
|
@ -318,8 +364,11 @@ maintain a persistent connection with each, you can use the
|
|||
`config.toml` or the `/dial_peers` RPC endpoint to do it without
|
||||
stopping Tendermint core instance.
|
||||
|
||||
```
|
||||
tendermint node --p2p.persistent_peers "429fcf25974313b95673f58d77eacdd434402665@10.11.12.13:26656,96663a3dd0d7b9d17d4c8211b191af259621c693@10.11.12.14:26656"
|
||||
|
||||
curl 'localhost:26657/dial_peers?persistent=true&peers=\["429fcf25974313b95673f58d77eacdd434402665@10.11.12.13:26656","96663a3dd0d7b9d17d4c8211b191af259621c693@10.11.12.14:26656"\]'
|
||||
```
|
||||
|
||||
### Adding a Non-Validator
|
||||
|
||||
|
@ -338,11 +387,14 @@ before starting the network. For instance, we could make a new
|
|||
|
||||
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" : "5AF49D2A2D4F5AD4C7C8C4CC2FB020131E9C4902",
|
||||
"pub_key" : {
|
||||
|
@ -357,9 +409,11 @@ Now we can update our genesis file. For instance, if the new
|
|||
"last_round" : "0",
|
||||
"last_height" : "0"
|
||||
}
|
||||
```
|
||||
|
||||
then the new `genesis.json` will be:
|
||||
|
||||
```
|
||||
{
|
||||
"validators" : [
|
||||
{
|
||||
|
@ -383,6 +437,7 @@ then the new `genesis.json` will be:
|
|||
"chain_id" : "test-chain-rDlYSN",
|
||||
"genesis_time" : "0001-01-01T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
Update the `genesis.json` in `~/.tendermint/config`. Copy the genesis
|
||||
file and the new `priv_validator.json` to the `~/.tendermint/config` on
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue