2018-06-06 09:16:53 -04:00
|
|
|
# Getting Started
|
|
|
|
|
|
|
|
## First Tendermint App
|
|
|
|
|
|
|
|
As a general purpose blockchain engine, Tendermint is agnostic to the
|
|
|
|
application you want to run. So, to run a complete blockchain that does
|
|
|
|
something useful, you must start two programs: one is Tendermint Core,
|
|
|
|
the other is your application, which can be written in any programming
|
|
|
|
language. Recall from [the intro to
|
2018-09-23 02:25:33 -04:00
|
|
|
ABCI](../introduction/introduction.html#abci-overview) that Tendermint Core handles all
|
2018-06-06 09:16:53 -04:00
|
|
|
the p2p and consensus stuff, and just forwards transactions to the
|
|
|
|
application when they need to be validated, or when they're ready to be
|
|
|
|
committed to a block.
|
|
|
|
|
|
|
|
In this guide, we show you some examples of how to run an application
|
|
|
|
using Tendermint.
|
|
|
|
|
|
|
|
### Install
|
|
|
|
|
|
|
|
The first apps we will work with are written in Go. To install them, you
|
|
|
|
need to [install Go](https://golang.org/doc/install) and put
|
|
|
|
`$GOPATH/bin` in your `$PATH`; see
|
|
|
|
[here](https://github.com/tendermint/tendermint/wiki/Setting-GOPATH) for
|
|
|
|
more info.
|
|
|
|
|
|
|
|
Then run
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
go get github.com/tendermint/tendermint
|
|
|
|
cd $GOPATH/src/github.com/tendermint/tendermint
|
|
|
|
make get_tools
|
|
|
|
make get_vendor_deps
|
|
|
|
make install_abci
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
Now you should have the `abci-cli` installed; you'll see a couple of
|
|
|
|
commands (`counter` and `kvstore`) that are example applications written
|
|
|
|
in Go. See below for an application written in JavaScript.
|
|
|
|
|
|
|
|
Now, let's run some apps!
|
|
|
|
|
|
|
|
## KVStore - A First Example
|
|
|
|
|
|
|
|
The kvstore app is a [Merkle
|
|
|
|
tree](https://en.wikipedia.org/wiki/Merkle_tree) that just stores all
|
|
|
|
transactions. If the transaction contains an `=`, e.g. `key=value`, then
|
|
|
|
the `value` is stored under the `key` in the Merkle tree. Otherwise, the
|
|
|
|
full transaction bytes are stored as the key and the value.
|
|
|
|
|
|
|
|
Let's start a kvstore application.
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
abci-cli kvstore
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
In another terminal, we can start Tendermint. If you have never run
|
|
|
|
Tendermint before, use:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
tendermint init
|
|
|
|
tendermint node
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
If you have used Tendermint, you may want to reset the data for a new
|
|
|
|
blockchain by running `tendermint unsafe_reset_all`. Then you can run
|
|
|
|
`tendermint node` to start Tendermint, and connect to the app. For more
|
2018-09-10 14:42:48 +08:00
|
|
|
details, see [the guide on using Tendermint](../tendermint-core/using-tendermint.md).
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
You should see Tendermint making blocks! We can get the status of our
|
|
|
|
Tendermint node as follows:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
curl -s localhost:26657/status
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
curl -s 'localhost:26657/broadcast_tx_commit?tx="abcd"'
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
Note the single quote (`'`) around the url, which ensures that the
|
|
|
|
double quotes (`"`) are not escaped by bash. This command sent a
|
|
|
|
transaction with bytes `abcd`, so `abcd` will be stored as both the key
|
|
|
|
and the value in the Merkle tree. The response should look something
|
|
|
|
like:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": "",
|
|
|
|
"result": {
|
2018-07-24 19:28:26 +04:00
|
|
|
"check_tx": {},
|
2018-07-04 12:00:57 -04:00
|
|
|
"deliver_tx": {
|
|
|
|
"tags": [
|
|
|
|
{
|
|
|
|
"key": "YXBwLmNyZWF0b3I=",
|
|
|
|
"value": "amFl"
|
2018-06-06 09:16:53 -04:00
|
|
|
},
|
2018-07-04 12:00:57 -04:00
|
|
|
{
|
|
|
|
"key": "YXBwLmtleQ==",
|
|
|
|
"value": "YWJjZA=="
|
|
|
|
}
|
2018-07-24 19:28:26 +04:00
|
|
|
]
|
2018-07-04 12:00:57 -04:00
|
|
|
},
|
|
|
|
"hash": "9DF66553F98DE3C26E3C3317A3E4CED54F714E39",
|
|
|
|
"height": 14
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
We can confirm that our transaction worked and the value got stored by
|
|
|
|
querying the app:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
curl -s 'localhost:26657/abci_query?data="abcd"'
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
The result should look like:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": "",
|
|
|
|
"result": {
|
|
|
|
"response": {
|
|
|
|
"log": "exists",
|
|
|
|
"index": "-1",
|
|
|
|
"key": "YWJjZA==",
|
|
|
|
"value": "YWJjZA=="
|
2018-06-06 09:16:53 -04:00
|
|
|
}
|
2018-07-04 12:00:57 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
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
|
2018-06-29 13:09:50 -05:00
|
|
|
running `"YWJjZA==".decode('base64')` or in python 3 shell by running
|
|
|
|
`import codecs; codecs.decode("YWJjZA==", 'base64').decode('ascii')`.
|
2018-06-06 09:16:53 -04:00
|
|
|
Stay tuned for a future release that [makes this output more
|
2018-06-22 18:16:51 -04:00
|
|
|
human-readable](https://github.com/tendermint/tendermint/issues/1794).
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
Now let's try setting a different key and value:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
curl -s 'localhost:26657/broadcast_tx_commit?tx="name=satoshi"'
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
Now if we query for `name`, we should get `satoshi`, or `c2F0b3NoaQ==`
|
|
|
|
in base64:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
curl -s 'localhost:26657/abci_query?data="name"'
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
Try some other transactions and queries to make sure everything is
|
|
|
|
working!
|
|
|
|
|
|
|
|
## Counter - Another Example
|
|
|
|
|
|
|
|
Now that we've got the hang of it, let's try another application, the
|
|
|
|
`counter` app.
|
|
|
|
|
|
|
|
The counter app doesn't use a Merkle tree, it just counts how many times
|
|
|
|
we've sent a transaction, or committed the state.
|
|
|
|
|
|
|
|
This application has two modes: `serial=off` and `serial=on`.
|
|
|
|
|
|
|
|
When `serial=on`, transactions must be a big-endian encoded incrementing
|
|
|
|
integer, starting at 0.
|
|
|
|
|
|
|
|
If `serial=off`, there are no restrictions on transactions.
|
|
|
|
|
|
|
|
In a live blockchain, transactions collect in memory before they are
|
|
|
|
committed into blocks. To avoid wasting resources on invalid
|
|
|
|
transactions, ABCI provides the `CheckTx` message, which application
|
|
|
|
developers can use to accept or reject transactions, before they are
|
|
|
|
stored in memory or gossipped to other peers.
|
|
|
|
|
|
|
|
In this instance of the counter app, with `serial=on`, `CheckTx` only
|
|
|
|
allows transactions whose integer is greater than the last committed
|
|
|
|
one.
|
|
|
|
|
|
|
|
Let's kill the previous instance of `tendermint` and the `kvstore`
|
|
|
|
application, and start the counter app. We can enable `serial=on` with a
|
|
|
|
flag:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
abci-cli counter --serial
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
In another window, reset then start Tendermint:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
tendermint unsafe_reset_all
|
|
|
|
tendermint node
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
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`:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
curl localhost:26657/broadcast_tx_commit?tx=0x00
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
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:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
> curl localhost:26657/broadcast_tx_commit?tx=0x05
|
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": "",
|
|
|
|
"result": {
|
2018-07-24 19:28:26 +04:00
|
|
|
"check_tx": {},
|
2018-07-04 12:00:57 -04:00
|
|
|
"deliver_tx": {
|
|
|
|
"code": 2,
|
2018-07-24 19:28:26 +04:00
|
|
|
"log": "Invalid nonce. Expected 1, got 5"
|
2018-07-04 12:00:57 -04:00
|
|
|
},
|
|
|
|
"hash": "33B93DFF98749B0D6996A70F64071347060DC19C",
|
|
|
|
"height": 34
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
But if we send a `1`, it works again:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
> curl localhost:26657/broadcast_tx_commit?tx=0x01
|
|
|
|
{
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"id": "",
|
|
|
|
"result": {
|
2018-07-24 19:28:26 +04:00
|
|
|
"check_tx": {},
|
|
|
|
"deliver_tx": {},
|
2018-07-04 12:00:57 -04:00
|
|
|
"hash": "F17854A977F6FA7EEA1BD758E296710B86F72F3D",
|
|
|
|
"height": 60
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
For more details on the `broadcast_tx` API, see [the guide on using
|
2018-09-10 14:42:48 +08:00
|
|
|
Tendermint](../tendermint-core/using-tendermint.md).
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
## CounterJS - Example in Another Language
|
|
|
|
|
|
|
|
We also want to run applications in another language - in this case,
|
|
|
|
we'll run a Javascript version of the `counter`. To run it, you'll need
|
|
|
|
to [install node](https://nodejs.org/en/download/).
|
|
|
|
|
|
|
|
You'll also need to fetch the relevant repository, from
|
|
|
|
[here](https://github.com/tendermint/js-abci) then install it. As go
|
|
|
|
devs, we keep all our code under the `$GOPATH`, so run:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
go get github.com/tendermint/js-abci &> /dev/null
|
|
|
|
cd $GOPATH/src/github.com/tendermint/js-abci/example
|
|
|
|
npm install
|
|
|
|
cd ..
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
Kill the previous `counter` and `tendermint` processes. Now run the app:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
node example/counter.js
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
In another window, reset and start `tendermint`:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
tendermint unsafe_reset_all
|
|
|
|
tendermint node
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
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:
|
|
|
|
|
2018-07-04 12:00:57 -04:00
|
|
|
```
|
|
|
|
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
|
|
|
|
```
|
2018-06-06 09:16:53 -04:00
|
|
|
|
|
|
|
Neat, eh?
|