getting started
This commit is contained in:
parent
2e18a4e633
commit
20e1eadcf1
|
@ -0,0 +1,265 @@
|
|||
# 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:46657/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:46657/broadcast_tx_commit?tx="abcd"'
|
||||
|
||||
Note the single quote (`'`) around the url, which ensures that the
|
||||
double quotes (`"`) are not escaped by bash. This command sent a
|
||||
transaction with bytes `abcd`, so `abcd` will be stored as both the key
|
||||
and the value in the Merkle tree. The response should look something
|
||||
like:
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
"result": {
|
||||
"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:46657/abci_query?data="abcd"'
|
||||
|
||||
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:46657/broadcast_tx_commit?tx="name=satoshi"'
|
||||
|
||||
Now if we query for `name`, we should get `satoshi`, or `c2F0b3NoaQ==`
|
||||
in base64:
|
||||
|
||||
curl -s 'localhost:46657/abci_query?data="name"'
|
||||
|
||||
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:46657/broadcast_tx_commit?tx=0x00
|
||||
|
||||
Note the empty (hence successful) response. The next transaction must be
|
||||
the number `1`. If instead, we try to send a `5`, we get an error:
|
||||
|
||||
> curl localhost:46657/broadcast_tx_commit?tx=0x05
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
"result": {
|
||||
"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:46657/broadcast_tx_commit?tx=0x01
|
||||
{
|
||||
"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:46657/broadcast_tx_commit?tx=0x00 # ok
|
||||
curl localhost:46657/broadcast_tx_commit?tx=0x05 # invalid nonce
|
||||
curl localhost:46657/broadcast_tx_commit?tx=0x01 # ok
|
||||
|
||||
Neat, eh?
|
|
@ -1,325 +0,0 @@
|
|||
First Tendermint App
|
||||
====================
|
||||
|
||||
As a general purpose blockchain engine, Tendermint is agnostic to the
|
||||
application you want to run. So, to run a complete blockchain that does
|
||||
something useful, you must start two programs: one is Tendermint Core,
|
||||
the other is your application, which can be written in any programming
|
||||
language. Recall from `the intro to ABCI <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:46657/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:46657/broadcast_tx_commit?tx="abcd"'
|
||||
|
||||
Note the single quote (``'``) around the url, which ensures that the
|
||||
double quotes (``"``) are not escaped by bash. This command sent a
|
||||
transaction with bytes ``abcd``, so ``abcd`` will be stored as both the
|
||||
key and the value in the Merkle tree. The response should look something
|
||||
like:
|
||||
|
||||
::
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
"result": {
|
||||
"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:46657/abci_query?data="abcd"'
|
||||
|
||||
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:46657/broadcast_tx_commit?tx="name=satoshi"'
|
||||
|
||||
Now if we query for ``name``, we should get ``satoshi``, or
|
||||
``c2F0b3NoaQ==`` in base64:
|
||||
|
||||
::
|
||||
|
||||
curl -s 'localhost:46657/abci_query?data="name"'
|
||||
|
||||
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:46657/broadcast_tx_commit?tx=0x00
|
||||
|
||||
Note the empty (hence successful) response. The next transaction must be
|
||||
the number ``1``. If instead, we try to send a ``5``, we get an error:
|
||||
|
||||
::
|
||||
|
||||
> curl localhost:46657/broadcast_tx_commit?tx=0x05
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": "",
|
||||
"result": {
|
||||
"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:46657/broadcast_tx_commit?tx=0x01
|
||||
{
|
||||
"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:46657/broadcast_tx_commit?tx=0x00 # ok
|
||||
curl localhost:46657/broadcast_tx_commit?tx=0x05 # invalid nonce
|
||||
curl localhost:46657/broadcast_tx_commit?tx=0x01 # ok
|
||||
|
||||
Neat, eh?
|
||||
|
||||
Basecoin - A More Interesting Example
|
||||
-------------------------------------
|
||||
|
||||
We saved the best for last; the `Cosmos SDK <https://github.com/cosmos/cosmos-sdk>`__ is a general purpose framework for building cryptocurrencies. Unlike the ``kvstore`` and ``counter``, which are strictly for example purposes. The reference implementation of Cosmos SDK is ``basecoin``, which demonstrates how to use the building blocks of the Cosmos SDK.
|
||||
|
||||
The default ``basecoin`` application is a multi-asset cryptocurrency
|
||||
that supports inter-blockchain communication (IBC). For more details on how
|
||||
basecoin works and how to use it, see our `basecoin
|
||||
guide <http://cosmos-sdk.readthedocs.io/en/latest/basecoin-basics.html>`__
|
||||
|
||||
In this tutorial you learned how to run applications using Tendermint
|
||||
on a single node. You saw how applications could be written in different
|
||||
languages, and how to send transactions and query for the latest state.
|
||||
But the true power of Tendermint comes from its ability to securely and
|
||||
efficiently run an application across a distributed network of nodes,
|
||||
while keeping them all in sync using its state-of-the-art consensus
|
||||
protocol. Next, we show you how to deploy Tendermint testnets.
|
Loading…
Reference in New Issue