tendermint/docs/getting-started.md

266 lines
7.9 KiB
Markdown
Raw Normal View History

2018-06-06 06:16:53 -07: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
ABCI](introduction.html#ABCI-Overview) that Tendermint Core handles all
the p2p and consensus stuff, and just forwards transactions to the
application when they need to be validated, or when they're ready to be
committed to a block.
In this guide, we show you some examples of how to run an application
using Tendermint.
### Install
The first apps we will work with are written in Go. To install them, you
need to [install Go](https://golang.org/doc/install) and put
`$GOPATH/bin` in your `$PATH`; see
[here](https://github.com/tendermint/tendermint/wiki/Setting-GOPATH) for
more info.
Then run
go get -u github.com/tendermint/abci/cmd/abci-cli
If there is an error, install and run the
[dep](https://github.com/golang/dep) tool to pin the dependencies:
cd $GOPATH/src/github.com/tendermint/abci
make get_tools
make get_vendor_deps
make install
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.
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
`tendermint node` to start Tendermint, and connect to the app. For more
details, see [the guide on using Tendermint](./using-tendermint.html).
You should see Tendermint making blocks! We can get the status of our
Tendermint node as follows:
curl -s localhost:26657/status
2018-06-06 06:16:53 -07: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.
curl -s 'localhost:26657/broadcast_tx_commit?tx="abcd"'
2018-06-06 06:16:53 -07: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:
{
"jsonrpc": "2.0",
"id": "",
"result": {
"check_tx": {
"fee": {}
},
"deliver_tx": {
"tags": [
{
"key": "YXBwLmNyZWF0b3I=",
"value": "amFl"
},
{
"key": "YXBwLmtleQ==",
"value": "YWJjZA=="
}
],
"fee": {}
},
"hash": "9DF66553F98DE3C26E3C3317A3E4CED54F714E39",
"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"'
2018-06-06 06:16:53 -07:00
The result should look like:
{
"jsonrpc": "2.0",
"id": "",
"result": {
"response": {
"log": "exists",
"index": "-1",
"key": "YWJjZA==",
"value": "YWJjZA=="
}
}
}
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
running `"61626364".decode('base64')` or in python 3 shell by running
`import codecs; codecs.decode("61626364", 'base64').decode('ascii')`.
Stay tuned for a future release that [makes this output more
human-readable](https://github.com/tendermint/abci/issues/32).
Now let's try setting a different key and value:
curl -s 'localhost:26657/broadcast_tx_commit?tx="name=satoshi"'
2018-06-06 06:16:53 -07:00
Now if we query for `name`, we should get `satoshi`, or `c2F0b3NoaQ==`
in base64:
curl -s 'localhost:26657/abci_query?data="name"'
2018-06-06 06:16:53 -07: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:
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
2018-06-06 06:16:53 -07: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:
> curl localhost:26657/broadcast_tx_commit?tx=0x05
2018-06-06 06:16:53 -07:00
{
"jsonrpc": "2.0",
"id": "",
"result": {
"check_tx": {
"fee": {}
},
"deliver_tx": {
"code": 2,
"log": "Invalid nonce. Expected 1, got 5",
"fee": {}
},
"hash": "33B93DFF98749B0D6996A70F64071347060DC19C",
"height": 34
}
}
But if we send a `1`, it works again:
> curl localhost:26657/broadcast_tx_commit?tx=0x01
2018-06-06 06:16:53 -07:00
{
"jsonrpc": "2.0",
"id": "",
"result": {
"check_tx": {
"fee": {}
},
"deliver_tx": {
"fee": {}
},
"hash": "F17854A977F6FA7EEA1BD758E296710B86F72F3D",
"height": 60
}
}
For more details on the `broadcast_tx` API, see [the guide on using
Tendermint](./using-tendermint.html).
## CounterJS - Example in Another Language
We also want to run applications in another language - in this case,
we'll run a Javascript version of the `counter`. To run it, you'll need
to [install node](https://nodejs.org/en/download/).
You'll also need to fetch the relevant repository, from
[here](https://github.com/tendermint/js-abci) then install it. As go
devs, we keep all our code under the `$GOPATH`, so run:
go get github.com/tendermint/js-abci &> /dev/null
cd $GOPATH/src/github.com/tendermint/js-abci/example
npm install
cd ..
Kill the previous `counter` and `tendermint` processes. Now run the app:
node example/app.js
In another window, reset and start `tendermint`:
tendermint unsafe_reset_all
tendermint node
Once again, you should see blocks streaming by - but now, our
application is written in javascript! Try sending some transactions, and
like before - the results should be the same:
curl localhost: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 06:16:53 -07:00
Neat, eh?