commit
1ecd580061
|
@ -28,8 +28,6 @@ const (
|
||||||
func isolate(cmds ...*cobra.Command) cli.Executable {
|
func isolate(cmds ...*cobra.Command) cli.Executable {
|
||||||
os.Unsetenv("TMHOME")
|
os.Unsetenv("TMHOME")
|
||||||
os.Unsetenv("TM_HOME")
|
os.Unsetenv("TM_HOME")
|
||||||
os.Unsetenv("TMROOT")
|
|
||||||
os.Unsetenv("TM_ROOT")
|
|
||||||
|
|
||||||
viper.Reset()
|
viper.Reset()
|
||||||
config = cfg.DefaultConfig()
|
config = cfg.DefaultConfig()
|
||||||
|
@ -70,7 +68,7 @@ func TestRootConfig(t *testing.T) {
|
||||||
{nil, nil, defaultRoot, defaults.Moniker, defaults.FastSync, dmax},
|
{nil, nil, defaultRoot, defaults.Moniker, defaults.FastSync, dmax},
|
||||||
// try multiple ways of setting root (two flags, cli vs. env)
|
// try multiple ways of setting root (two flags, cli vs. env)
|
||||||
{[]string{"--home", conf}, nil, conf, cvals["moniker"], cfast, dmax},
|
{[]string{"--home", conf}, nil, conf, cvals["moniker"], cfast, dmax},
|
||||||
{nil, map[string]string{"TMROOT": conf}, conf, cvals["moniker"], cfast, dmax},
|
{nil, map[string]string{"TMHOME": conf}, conf, cvals["moniker"], cfast, dmax},
|
||||||
// check setting p2p subflags two different ways
|
// check setting p2p subflags two different ways
|
||||||
{[]string{"--p2p.max_num_peers", "420"}, nil, defaultRoot, defaults.Moniker, defaults.FastSync, 420},
|
{[]string{"--p2p.max_num_peers", "420"}, nil, defaultRoot, defaults.Moniker, defaults.FastSync, 420},
|
||||||
{nil, map[string]string{"TM_P2P_MAX_NUM_PEERS": "17"}, defaultRoot, defaults.Moniker, defaults.FastSync, 17},
|
{nil, map[string]string{"TM_P2P_MAX_NUM_PEERS": "17"}, defaultRoot, defaults.Moniker, defaults.FastSync, 17},
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
.toggle {
|
||||||
|
padding-bottom: 1em ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle .header {
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle .header:after {
|
||||||
|
content: " ▼";
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle .header.open:after {
|
||||||
|
content: " ▲";
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
let makeCodeBlocksCollapsible = function() {
|
||||||
|
$(".toggle > *").hide();
|
||||||
|
$(".toggle .header").show();
|
||||||
|
$(".toggle .header").click(function() {
|
||||||
|
$(this).parent().children().not(".header").toggle({"duration": 400});
|
||||||
|
$(this).parent().children(".header").toggleClass("open");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// we could use the }(); way if we would have access to jQuery in HEAD, i.e. we would need to force the theme
|
||||||
|
// to load jQuery before our custom scripts
|
|
@ -0,0 +1,20 @@
|
||||||
|
{% extends "!layout.html" %}
|
||||||
|
|
||||||
|
{% set css_files = css_files + ["_static/custom_collapsible_code.css"] %}
|
||||||
|
|
||||||
|
# sadly, I didn't find a css style way to add custom JS to a list that is automagically added to head like CSS (above) #}
|
||||||
|
{% block extrahead %}
|
||||||
|
<script type="text/javascript" src="_static/custom_collapsible_code.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block footer %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
// using this approach as we don't have access to the jQuery selectors
|
||||||
|
// when executing the function on load in HEAD
|
||||||
|
makeCodeBlocksCollapsible();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ Next, install the ``abci-cli`` tool and example applications:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
go get -u github.com/tendermint/abci/cmd/...
|
go get -u github.com/tendermint/abci/cmd/abci-cli
|
||||||
|
|
||||||
If this fails, you may need to use ``glide`` to get vendored
|
If this fails, you may need to use ``glide`` to get vendored
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -24,27 +24,37 @@ dependencies:
|
||||||
go get github.com/Masterminds/glide
|
go get github.com/Masterminds/glide
|
||||||
cd $GOPATH/src/github.com/tendermint/abci
|
cd $GOPATH/src/github.com/tendermint/abci
|
||||||
glide install
|
glide install
|
||||||
go install ./cmd/...
|
go install ./cmd/abci-cli
|
||||||
|
|
||||||
Now run ``abci-cli --help`` to see the list of commands:
|
Now run ``abci-cli`` to see the list of commands:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
COMMANDS:
|
Usage:
|
||||||
batch Run a batch of ABCI commands against an application
|
abci-cli [command]
|
||||||
console Start an interactive console for multiple commands
|
|
||||||
echo Have the application echo a message
|
Available Commands:
|
||||||
info Get some info about the application
|
batch Run a batch of abci commands against an application
|
||||||
set_option Set an option on the application
|
check_tx Validate a tx
|
||||||
deliver_tx Append a new tx to application
|
commit Commit the application state and return the Merkle root hash
|
||||||
check_tx Validate a tx
|
console Start an interactive abci console for multiple commands
|
||||||
commit Get application Merkle root hash
|
counter ABCI demo example
|
||||||
help, h Shows a list of commands or help for one command
|
deliver_tx Deliver a new tx to the application
|
||||||
|
dummy ABCI demo example
|
||||||
|
echo Have the application echo a message
|
||||||
|
help Help about any command
|
||||||
|
info Get some info about the application
|
||||||
|
query Query the application state
|
||||||
|
set_option Set an options on the application
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
--abci string socket or grpc (default "socket")
|
||||||
|
--address string address of application socket (default "tcp://127.0.0.1:46658")
|
||||||
|
-h, --help help for abci-cli
|
||||||
|
-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.
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
|
||||||
--address "tcp://127.0.0.1:46658" address of application socket
|
|
||||||
--help, -h show help
|
|
||||||
--version, -v print the version
|
|
||||||
|
|
||||||
Dummy - First Example
|
Dummy - First Example
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -61,7 +71,7 @@ Let's start a dummy application, which was installed at the same time as
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
dummy
|
abci-cli dummy
|
||||||
|
|
||||||
In another terminal, run
|
In another terminal, run
|
||||||
|
|
||||||
|
@ -70,8 +80,19 @@ In another terminal, run
|
||||||
abci-cli echo hello
|
abci-cli echo hello
|
||||||
abci-cli info
|
abci-cli info
|
||||||
|
|
||||||
The application should echo ``hello`` and give you some information
|
You'll see something like:
|
||||||
about itself.
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-> data: hello
|
||||||
|
-> data.hex: 68656C6C6F
|
||||||
|
|
||||||
|
and:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-> data: {"size":0}
|
||||||
|
-> data.hex: 7B2273697A65223A307D
|
||||||
|
|
||||||
An ABCI application must provide two things:
|
An ABCI application must provide two things:
|
||||||
|
|
||||||
|
@ -86,7 +107,7 @@ The server may be generic for a particular language, and we provide a
|
||||||
`reference implementation in
|
`reference implementation in
|
||||||
Golang <https://github.com/tendermint/abci/tree/master/server>`__. See
|
Golang <https://github.com/tendermint/abci/tree/master/server>`__. See
|
||||||
the `list of other ABCI
|
the `list of other ABCI
|
||||||
implementations <https://tendermint.com/ecosystem>`__ for servers in
|
implementations <./ecosystem.html>`__ for servers in
|
||||||
other languages.
|
other languages.
|
||||||
|
|
||||||
The handler is specific to the application, and may be arbitrary, so
|
The handler is specific to the application, and may be arbitrary, so
|
||||||
|
@ -109,36 +130,50 @@ Try running these commands:
|
||||||
::
|
::
|
||||||
|
|
||||||
> echo hello
|
> echo hello
|
||||||
|
-> code: OK
|
||||||
-> data: hello
|
-> data: hello
|
||||||
|
-> data.hex: 0x68656C6C6F
|
||||||
|
|
||||||
> info
|
> info
|
||||||
|
-> code: OK
|
||||||
-> data: {"size":0}
|
-> data: {"size":0}
|
||||||
|
-> data.hex: 0x7B2273697A65223A307D
|
||||||
|
|
||||||
> commit
|
> commit
|
||||||
-> data: 0x
|
-> code: OK
|
||||||
|
|
||||||
> deliver_tx "abc"
|
> deliver_tx "abc"
|
||||||
-> code: OK
|
-> code: OK
|
||||||
|
|
||||||
> info
|
> info
|
||||||
|
-> code: OK
|
||||||
-> data: {"size":1}
|
-> data: {"size":1}
|
||||||
|
-> data.hex: 0x7B2273697A65223A317D
|
||||||
|
|
||||||
> commit
|
> commit
|
||||||
-> data: 0x750502FC7E84BBD788ED589624F06CFA871845D1
|
-> code: OK
|
||||||
|
-> data.hex: 0x49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91
|
||||||
|
|
||||||
> query "abc"
|
> query "abc"
|
||||||
-> code: OK
|
-> code: OK
|
||||||
-> data: {"index":0,"value":"abc","exists":true}
|
-> log: exists
|
||||||
|
-> height: 0
|
||||||
|
-> value: abc
|
||||||
|
-> value.hex: 616263
|
||||||
|
|
||||||
> deliver_tx "def=xyz"
|
> deliver_tx "def=xyz"
|
||||||
-> code: OK
|
-> code: OK
|
||||||
|
|
||||||
> commit
|
> commit
|
||||||
-> data: 0x76393B8A182E450286B0694C629ECB51B286EFD5
|
-> code: OK
|
||||||
|
-> data.hex: 0x70102DB32280373FBF3F9F89DA2A20CE2CD62B0B
|
||||||
|
|
||||||
> query "def"
|
> query "def"
|
||||||
-> code: OK
|
-> code: OK
|
||||||
-> data: {"index":1,"value":"xyz","exists":true}
|
-> log: exists
|
||||||
|
-> height: 0
|
||||||
|
-> value: xyz
|
||||||
|
-> value.hex: 78797A
|
||||||
|
|
||||||
Note that if we do ``deliver_tx "abc"`` it will store ``(abc, abc)``,
|
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)``.
|
but if we do ``deliver_tx "abc=efg"`` it will store ``(abc, efg)``.
|
||||||
|
@ -181,14 +216,14 @@ app:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
counter
|
abci-cli counter
|
||||||
|
|
||||||
In another window, start the ``abci-cli console``:
|
In another window, start the ``abci-cli console``:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
> set_option serial on
|
> set_option serial on
|
||||||
-> data: serial=on
|
-> code: OK
|
||||||
|
|
||||||
> check_tx 0x00
|
> check_tx 0x00
|
||||||
-> code: OK
|
-> code: OK
|
||||||
|
@ -211,7 +246,9 @@ In another window, start the ``abci-cli console``:
|
||||||
-> log: Invalid nonce. Expected 2, got 4
|
-> log: Invalid nonce. Expected 2, got 4
|
||||||
|
|
||||||
> info
|
> info
|
||||||
|
-> code: OK
|
||||||
-> data: {"hashes":0,"txs":2}
|
-> data: {"hashes":0,"txs":2}
|
||||||
|
-> data.hex: 0x7B22686173686573223A302C22747873223A327D
|
||||||
|
|
||||||
This is a very simple application, but between ``counter`` and
|
This is a very simple application, but between ``counter`` and
|
||||||
``dummy``, its easy to see how you can build out arbitrary application
|
``dummy``, its easy to see how you can build out arbitrary application
|
||||||
|
|
|
@ -194,12 +194,38 @@ through all transactions in the mempool, removing any that were included
|
||||||
in the block, and re-run the rest using CheckTx against the post-Commit
|
in the block, and re-run the rest using CheckTx against the post-Commit
|
||||||
mempool state.
|
mempool state.
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
func (app *DummyApplication) CheckTx(tx []byte) types.Result {
|
func (app *DummyApplication) CheckTx(tx []byte) types.Result {
|
||||||
return types.OK
|
return types.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
ResponseCheckTx requestCheckTx(RequestCheckTx req) {
|
||||||
|
byte[] transaction = req.getTx().toByteArray();
|
||||||
|
|
||||||
|
// validate transaction
|
||||||
|
|
||||||
|
if (notValid) {
|
||||||
|
return ResponseCheckTx.newBuilder().setCode(CodeType.BadNonce).setLog("invalid tx").build();
|
||||||
|
} else {
|
||||||
|
return ResponseCheckTx.newBuilder().setCode(CodeType.OK).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Consensus Connection
|
Consensus Connection
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -228,7 +254,13 @@ The block header will be updated (TODO) to include some commitment to
|
||||||
the results of DeliverTx, be it a bitarray of non-OK transactions, or a
|
the results of DeliverTx, be it a bitarray of non-OK transactions, or a
|
||||||
merkle root of the data returned by the DeliverTx requests, or both.
|
merkle root of the data returned by the DeliverTx requests, or both.
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
// tx is either "key=value" or just arbitrary bytes
|
// tx is either "key=value" or just arbitrary bytes
|
||||||
func (app *DummyApplication) DeliverTx(tx []byte) types.Result {
|
func (app *DummyApplication) DeliverTx(tx []byte) types.Result {
|
||||||
|
@ -241,6 +273,30 @@ merkle root of the data returned by the DeliverTx requests, or both.
|
||||||
return types.OK
|
return types.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using Protobuf types from the protoc compiler, we always start with a byte[]
|
||||||
|
*/
|
||||||
|
ResponseDeliverTx deliverTx(RequestDeliverTx request) {
|
||||||
|
byte[] transaction = request.getTx().toByteArray();
|
||||||
|
|
||||||
|
// validate your transaction
|
||||||
|
|
||||||
|
if (notValid) {
|
||||||
|
return ResponseDeliverTx.newBuilder().setCode(CodeType.BadNonce).setLog("transaction was invalid").build();
|
||||||
|
} else {
|
||||||
|
ResponseDeliverTx.newBuilder().setCode(CodeType.OK).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Commit
|
Commit
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
|
@ -263,13 +319,36 @@ It is expected that the app will persist state to disk on Commit. The
|
||||||
option to have all transactions replayed from some previous block is the
|
option to have all transactions replayed from some previous block is the
|
||||||
job of the `Handshake <#handshake>`__.
|
job of the `Handshake <#handshake>`__.
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
func (app *DummyApplication) Commit() types.Result {
|
func (app *DummyApplication) Commit() types.Result {
|
||||||
hash := app.state.Hash()
|
hash := app.state.Hash()
|
||||||
return types.NewResultOK(hash, "")
|
return types.NewResultOK(hash, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
ResponseCommit requestCommit(RequestCommit requestCommit) {
|
||||||
|
|
||||||
|
// update the internal app-state
|
||||||
|
byte[] newAppState = calculateAppState();
|
||||||
|
|
||||||
|
// and return it to the node
|
||||||
|
return ResponseCommit.newBuilder().setCode(CodeType.OK).setData(ByteString.copyFrom(newAppState)).build();
|
||||||
|
}
|
||||||
|
|
||||||
BeginBlock
|
BeginBlock
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -281,7 +360,13 @@ The app should remember the latest height and header (ie. from which it
|
||||||
has run a successful Commit) so that it can tell Tendermint where to
|
has run a successful Commit) so that it can tell Tendermint where to
|
||||||
pick up from when it restarts. See information on the Handshake, below.
|
pick up from when it restarts. See information on the Handshake, below.
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
// Track the block hash and header information
|
// Track the block hash and header information
|
||||||
func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) {
|
func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) {
|
||||||
|
@ -292,6 +377,29 @@ pick up from when it restarts. See information on the Handshake, below.
|
||||||
app.changes = make([]*types.Validator, 0)
|
app.changes = make([]*types.Validator, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
/*
|
||||||
|
* all types come from protobuf definition
|
||||||
|
*/
|
||||||
|
ResponseBeginBlock requestBeginBlock(RequestBeginBlock req) {
|
||||||
|
|
||||||
|
Header header = req.getHeader();
|
||||||
|
byte[] prevAppHash = header.getAppHash().toByteArray();
|
||||||
|
long prevHeight = header.getHeight();
|
||||||
|
long numTxs = header.getNumTxs();
|
||||||
|
|
||||||
|
// run your pre-block logic. Maybe prepare a state snapshot, message components, etc
|
||||||
|
|
||||||
|
return ResponseBeginBlock.newBuilder().build();
|
||||||
|
}
|
||||||
|
|
||||||
EndBlock
|
EndBlock
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
|
@ -304,13 +412,40 @@ EndBlock response. To remove one, include it in the list with a
|
||||||
validator set. Note validator set changes are only available in v0.8.0
|
validator set. Note validator set changes are only available in v0.8.0
|
||||||
and up.
|
and up.
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
// Update the validator set
|
// Update the validator set
|
||||||
func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) {
|
func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) {
|
||||||
return types.ResponseEndBlock{Diffs: app.changes}
|
return types.ResponseEndBlock{Diffs: app.changes}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume that one validator changes. The new validator has a power of 10
|
||||||
|
*/
|
||||||
|
ResponseEndBlock requestEndBlock(RequestEndBlock req) {
|
||||||
|
final long currentHeight = req.getHeight();
|
||||||
|
final byte[] validatorPubKey = getValPubKey();
|
||||||
|
|
||||||
|
ResponseEndBlock.Builder builder = ResponseEndBlock.newBuilder();
|
||||||
|
builder.addDiffs(1, Types.Validator.newBuilder().setPower(10L).setPubKey(ByteString.copyFrom(validatorPubKey)).build());
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
Query Connection
|
Query Connection
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -332,7 +467,13 @@ cause Tendermint to not connect to the corresponding peer:
|
||||||
|
|
||||||
Note: these query formats are subject to change!
|
Note: these query formats are subject to change!
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||||
if reqQuery.Prove {
|
if reqQuery.Prove {
|
||||||
|
@ -360,6 +501,39 @@ Note: these query formats are subject to change!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
ResponseQuery requestQuery(RequestQuery req) {
|
||||||
|
final boolean isProveQuery = req.getProve();
|
||||||
|
final ResponseQuery.Builder responseBuilder = ResponseQuery.newBuilder();
|
||||||
|
|
||||||
|
if (isProveQuery) {
|
||||||
|
com.app.example.ProofResult proofResult = generateProof(req.getData().toByteArray());
|
||||||
|
final byte[] proofAsByteArray = proofResult.getAsByteArray();
|
||||||
|
|
||||||
|
responseBuilder.setProof(ByteString.copyFrom(proofAsByteArray));
|
||||||
|
responseBuilder.setKey(req.getData());
|
||||||
|
responseBuilder.setValue(ByteString.copyFrom(proofResult.getData()));
|
||||||
|
responseBuilder.setLog(result.getLogValue());
|
||||||
|
} else {
|
||||||
|
byte[] queryData = req.getData().toByteArray();
|
||||||
|
|
||||||
|
final com.app.example.QueryResult result = generateQueryResult(queryData);
|
||||||
|
|
||||||
|
responseBuilder.setIndex(result.getIndex());
|
||||||
|
responseBuilder.setValue(ByteString.copyFrom(result.getValue()));
|
||||||
|
responseBuilder.setLog(result.getLogValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
Handshake
|
Handshake
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
|
@ -377,12 +551,32 @@ the app are synced to the latest block height.
|
||||||
If the app returns a LastBlockHeight of 0, Tendermint will just replay
|
If the app returns a LastBlockHeight of 0, Tendermint will just replay
|
||||||
all blocks.
|
all blocks.
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
||||||
return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())}
|
return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
ResponseInfo requestInfo(RequestInfo req) {
|
||||||
|
final byte[] lastAppHash = getLastAppHash();
|
||||||
|
final long lastHeight = getLastHeight();
|
||||||
|
return ResponseInfo.newBuilder().setLastBlockAppHash(ByteString.copyFrom(lastAppHash)).setLastBlockHeight(lastHeight).build();
|
||||||
|
}
|
||||||
|
|
||||||
Genesis
|
Genesis
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
|
@ -390,7 +584,13 @@ Genesis
|
||||||
initial validator set. Later on, it may be extended to take parts of the
|
initial validator set. Later on, it may be extended to take parts of the
|
||||||
consensus params.
|
consensus params.
|
||||||
|
|
||||||
::
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Go Example**
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
// Save the validators in the merkle tree
|
// Save the validators in the merkle tree
|
||||||
func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) {
|
func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) {
|
||||||
|
@ -401,3 +601,28 @@ consensus params.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. container:: toggle
|
||||||
|
|
||||||
|
.. container:: header
|
||||||
|
|
||||||
|
**Show/Hide Java Example**
|
||||||
|
|
||||||
|
.. code-block:: java
|
||||||
|
|
||||||
|
/*
|
||||||
|
* all types come from protobuf definition
|
||||||
|
*/
|
||||||
|
ResponseInitChain requestInitChain(RequestInitChain req) {
|
||||||
|
final int validatorsCount = req.getValidatorsCount();
|
||||||
|
final List<Types.Validator> validatorsList = req.getValidatorsList();
|
||||||
|
|
||||||
|
validatorsList.forEach((validator) -> {
|
||||||
|
long power = validator.getPower();
|
||||||
|
byte[] validatorPubKey = validator.getPubKey().toByteArray();
|
||||||
|
|
||||||
|
// do somehing for validator setup in app
|
||||||
|
});
|
||||||
|
|
||||||
|
return ResponseInitChain.newBuilder().build();
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ It's relatively easy to setup a Tendermint cluster manually. The only
|
||||||
requirements for a particular Tendermint node are a private key for the
|
requirements for a particular Tendermint node are a private key for the
|
||||||
validator, stored as ``priv_validator.json``, and a list of the public
|
validator, stored as ``priv_validator.json``, and a list of the public
|
||||||
keys of all validators, stored as ``genesis.json``. These files should
|
keys of all validators, stored as ``genesis.json``. These files should
|
||||||
be stored in ``~/.tendermint``, or wherever the ``$TMROOT`` variable
|
be stored in ``~/.tendermint``, or wherever the ``$TMHOME`` variable
|
||||||
might be set to.
|
might be set to.
|
||||||
|
|
||||||
Here are the steps to setting up a testnet manually:
|
Here are the steps to setting up a testnet manually:
|
||||||
|
|
|
@ -115,3 +115,8 @@ Deployment Tools
|
||||||
See `deploy testnets <./deploy-testnets.html>`__ for information about all the tools built by Tendermint. We have Kubernetes, Ansible, and Terraform integrations.
|
See `deploy testnets <./deploy-testnets.html>`__ for information about all the tools built by Tendermint. We have Kubernetes, Ansible, and Terraform integrations.
|
||||||
|
|
||||||
Cloudsoft built `brooklyn-tendermint <https://github.com/cloudsoft/brooklyn-tendermint>`__ for deploying a tendermint testnet in docker continers. It uses Clocker for Apache Brooklyn.
|
Cloudsoft built `brooklyn-tendermint <https://github.com/cloudsoft/brooklyn-tendermint>`__ for deploying a tendermint testnet in docker continers. It uses Clocker for Apache Brooklyn.
|
||||||
|
|
||||||
|
Dev Tools
|
||||||
|
---------
|
||||||
|
|
||||||
|
For upgrading from older to newer versions of tendermint and to migrate your chain data, see `tm-migrator <https://github.com/hxzqlh/tm-tools>`__ written by @hxzqlh.
|
||||||
|
|
|
@ -25,7 +25,7 @@ Then run
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
go get -u github.com/tendermint/abci/cmd/...
|
go get -u github.com/tendermint/abci/cmd/abci-cli
|
||||||
|
|
||||||
If there is an error, install and run the ``glide`` tool to pin the
|
If there is an error, install and run the ``glide`` tool to pin the
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -35,20 +35,12 @@ dependencies:
|
||||||
go get github.com/Masterminds/glide
|
go get github.com/Masterminds/glide
|
||||||
cd $GOPATH/src/github.com/tendermint/abci
|
cd $GOPATH/src/github.com/tendermint/abci
|
||||||
glide install
|
glide install
|
||||||
go install ./cmd/...
|
go install ./cmd/abci-cli
|
||||||
|
|
||||||
Now you should have the ``abci-cli`` plus two apps installed:
|
Now you should have the ``abci-cli`` installed; you'll see
|
||||||
|
a couple of commands (``counter`` and ``dummy``) that are
|
||||||
::
|
example applications written in Go. See below for an application
|
||||||
|
written in Javascript.
|
||||||
dummy --help
|
|
||||||
counter --help
|
|
||||||
|
|
||||||
These binaries are installed on ``$GOPATH/bin`` and all come from within
|
|
||||||
the ``./cmd/...`` directory of the abci repository.
|
|
||||||
|
|
||||||
Both of these example applications are in Go. See below for an
|
|
||||||
application written in Javascript.
|
|
||||||
|
|
||||||
Now, let's run some apps!
|
Now, let's run some apps!
|
||||||
|
|
||||||
|
@ -66,7 +58,7 @@ Let's start a dummy application.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
dummy
|
abci-cli dummy
|
||||||
|
|
||||||
In another terminal, we can start Tendermint. If you have never run
|
In another terminal, we can start Tendermint. If you have never run
|
||||||
Tendermint before, use:
|
Tendermint before, use:
|
||||||
|
@ -126,10 +118,6 @@ like:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
The ``98`` is a type-byte, and can be ignored (it's useful for
|
|
||||||
serializing and deserializing arbitrary json). Otherwise, this result is
|
|
||||||
empty - there's nothing to report on and everything is OK.
|
|
||||||
|
|
||||||
We can confirm that our transaction worked and the value got stored by
|
We can confirm that our transaction worked and the value got stored by
|
||||||
querying the app:
|
querying the app:
|
||||||
|
|
||||||
|
@ -157,11 +145,10 @@ The result should look like:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Again, the ``112`` is the type-byte. Note the ``value`` in the result
|
Note the ``value`` in the result (``61626364``); this is the
|
||||||
(``61626364``); this is the hex-encoding of the ASCII of ``abcd``. You
|
hex-encoding of the ASCII of ``abcd``. You can verify this in
|
||||||
can verify this in a python shell by running
|
a python shell by running ``"61626364".decode('hex')``. Stay
|
||||||
``"61626364".decode('hex')``. Stay tuned for a future release that makes
|
tuned for a future release that `makes this output more human-readable <https://github.com/tendermint/abci/issues/32>`__.
|
||||||
this output more human-readable ;).
|
|
||||||
|
|
||||||
Now let's try setting a different key and value:
|
Now let's try setting a different key and value:
|
||||||
|
|
||||||
|
@ -183,7 +170,7 @@ Counter - Another Example
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Now that we've got the hang of it, let's try another application, the
|
Now that we've got the hang of it, let's try another application, the
|
||||||
"counter" app.
|
**counter** app.
|
||||||
|
|
||||||
The counter app doesn't use a Merkle tree, it just counts how many times
|
The counter app doesn't use a Merkle tree, it just counts how many times
|
||||||
we've sent a transaction, or committed the state.
|
we've sent a transaction, or committed the state.
|
||||||
|
@ -211,7 +198,7 @@ a flag:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
counter --serial
|
abci-cli counter --serial
|
||||||
|
|
||||||
In another window, reset then start Tendermint:
|
In another window, reset then start Tendermint:
|
||||||
|
|
||||||
|
@ -295,6 +282,7 @@ keep all our code under the ``$GOPATH``, so run:
|
||||||
go get github.com/tendermint/js-abci &> /dev/null
|
go get github.com/tendermint/js-abci &> /dev/null
|
||||||
cd $GOPATH/src/github.com/tendermint/js-abci/example
|
cd $GOPATH/src/github.com/tendermint/js-abci/example
|
||||||
npm install
|
npm install
|
||||||
|
cd ..
|
||||||
|
|
||||||
Kill the previous ``counter`` and ``tendermint`` processes. Now run the
|
Kill the previous ``counter`` and ``tendermint`` processes. Now run the
|
||||||
app:
|
app:
|
||||||
|
@ -328,9 +316,9 @@ 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 ``dummy`` 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.
|
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 ``dummy`` 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
|
The default ``basecoin`` application is a multi-asset cryptocurrency
|
||||||
that supports inter-blockchain communication. For more details on how
|
that supports inter-blockchain communication (IBC). For more details on how
|
||||||
basecoin works and how to use it, see our `basecoin
|
basecoin works and how to use it, see our `basecoin
|
||||||
guide <https://github.com/cosmos/cosmos-sdk/blob/develop/docs/guide/basecoin-basics.md>`__
|
guide <http://cosmos-sdk.readthedocs.io/en/latest/basecoin-basics.html>`__
|
||||||
|
|
||||||
In this tutorial you learned how to run applications using Tendermint
|
In this tutorial you learned how to run applications using Tendermint
|
||||||
on a single node. You saw how applications could be written in different
|
on a single node. You saw how applications could be written in different
|
||||||
|
|
|
@ -8,8 +8,8 @@ Welcome to Tendermint!
|
||||||
|
|
||||||
|
|
||||||
.. image:: assets/tmint-logo-blue.png
|
.. image:: assets/tmint-logo-blue.png
|
||||||
:height: 500px
|
:height: 200px
|
||||||
:width: 500px
|
:width: 200px
|
||||||
:align: center
|
:align: center
|
||||||
|
|
||||||
Tendermint 101
|
Tendermint 101
|
||||||
|
|
|
@ -9,7 +9,7 @@ To download pre-built binaries, see the `Download page <https://tendermint.com/d
|
||||||
From Source
|
From Source
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
You'll need `go`, maybe `glide` and the tendermint source code.
|
You'll need ``go``, maybe ``glide``, and the tendermint source code.
|
||||||
|
|
||||||
Install Go
|
Install Go
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
|
@ -146,11 +146,11 @@ The ABCI consists of 3 primary message types that get delivered from the core to
|
||||||
|
|
||||||
The messages are specified here: `ABCI Message Types <https://github.com/tendermint/abci#message-types>`__.
|
The messages are specified here: `ABCI Message Types <https://github.com/tendermint/abci#message-types>`__.
|
||||||
|
|
||||||
The `DeliverTx` message is the work horse of the application. Each transaction in the blockchain is delivered with this message. The application needs to validate each transaction received with the `DeliverTx` message against the current state, application protocol, and the cryptographic credentials of the transaction. A validated transaction then needs to update the application state — by binding a value into a key values store, or by updating the UTXO database, for instance.
|
The **DeliverTx** message is the work horse of the application. Each transaction in the blockchain is delivered with this message. The application needs to validate each transaction received with the **DeliverTx** message against the current state, application protocol, and the cryptographic credentials of the transaction. A validated transaction then needs to update the application state — by binding a value into a key values store, or by updating the UTXO database, for instance.
|
||||||
|
|
||||||
The `CheckTx` message is similar to `DeliverTx`, but it's only for validating transactions. Tendermint Core's mempool first checks the validity of a transaction with `CheckTx`, and only relays valid transactions to its peers. For instance, an application may check an incrementing sequence number in the transaction and return an error upon `CheckTx` if the sequence number is old. Alternatively, they might use a capabilities based system that requires capabilities to be renewed with every transaction.
|
The **CheckTx** message is similar to **DeliverTx**, but it's only for validating transactions. Tendermint Core's mempool first checks the validity of a transaction with **CheckTx**, and only relays valid transactions to its peers. For instance, an application may check an incrementing sequence number in the transaction and return an error upon **CheckTx** if the sequence number is old. Alternatively, they might use a capabilities based system that requires capabilities to be renewed with every transaction.
|
||||||
|
|
||||||
The `Commit` message is used to compute a cryptographic commitment to the current application state, to be placed into the next block header. This has some handy properties. Inconsistencies in updating that state will now appear as blockchain forks which catches a whole class of programming errors. This also simplifies the development of secure lightweight clients, as Merkle-hash proofs can be verified by checking against the block hash, and that the block hash is signed by a quorum.
|
The **Commit** message is used to compute a cryptographic commitment to the current application state, to be placed into the next block header. This has some handy properties. Inconsistencies in updating that state will now appear as blockchain forks which catches a whole class of programming errors. This also simplifies the development of secure lightweight clients, as Merkle-hash proofs can be verified by checking against the block hash, and that the block hash is signed by a quorum.
|
||||||
|
|
||||||
There can be multiple ABCI socket connections to an application. Tendermint Core creates three ABCI connections to the application; one for the validation of transactions when broadcasting in the mempool, one for the consensus engine to run block proposals, and one more for querying the application state.
|
There can be multiple ABCI socket connections to an application. Tendermint Core creates three ABCI connections to the application; one for the validation of transactions when broadcasting in the mempool, one for the consensus engine to run block proposals, and one more for querying the application state.
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ Solidity on Ethereum is a great language of choice for blockchain applications b
|
||||||
* race conditions on threads (or avoiding threads altogether)
|
* race conditions on threads (or avoiding threads altogether)
|
||||||
* the system clock
|
* the system clock
|
||||||
* uninitialized memory (in unsafe programming languages like C or C++)
|
* uninitialized memory (in unsafe programming languages like C or C++)
|
||||||
* `floating point arithmetic <http://gafferongames.com/networking-for-game-programmers/floating-point-determinism/>`__.
|
* `floating point arithmetic <http://gafferongames.com/networking-for-game-programmers/floating-point-determinism/>`__
|
||||||
* language features that are random (e.g. map iteration in Go)
|
* language features that are random (e.g. map iteration in Go)
|
||||||
|
|
||||||
While programmers can avoid non-determinism by being careful, it is also possible to create a special linter or static analyzer for each language to check for determinism. In the future we may work with partners to create such tools.
|
While programmers can avoid non-determinism by being careful, it is also possible to create a special linter or static analyzer for each language to check for determinism. In the future we may work with partners to create such tools.
|
||||||
|
@ -182,17 +182,17 @@ The protocol follows a simple state machine that looks like this:
|
||||||
|
|
||||||
.. figure:: assets/consensus_logic.png
|
.. figure:: assets/consensus_logic.png
|
||||||
|
|
||||||
Participants in the protocol are called "validators";
|
Participants in the protocol are called **validators**;
|
||||||
they take turns proposing blocks of transactions and voting on them.
|
they take turns proposing blocks of transactions and voting on them.
|
||||||
Blocks are committed in a chain, with one block at each "height".
|
Blocks are committed in a chain, with one block at each **height**.
|
||||||
A block may fail to be committed, in which case the protocol moves to the next "round",
|
A block may fail to be committed, in which case the protocol moves to the next **round**,
|
||||||
and a new validator gets to propose a block for that height.
|
and a new validator gets to propose a block for that height.
|
||||||
Two stages of voting are required to successfully commit a block;
|
Two stages of voting are required to successfully commit a block;
|
||||||
we call them "pre-vote" and "pre-commit".
|
we call them **pre-vote** and **pre-commit**.
|
||||||
A block is committed when more than 2/3 of validators pre-commit for the same block in the same round.
|
A block is committed when more than 2/3 of validators pre-commit for the same block in the same round.
|
||||||
|
|
||||||
There is a picture of a couple doing the polka because validators are doing something like a polka dance.
|
There is a picture of a couple doing the polka because validators are doing something like a polka dance.
|
||||||
When more than two-thirds of the validators pre-vote for the same block, we call that a "polka".
|
When more than two-thirds of the validators pre-vote for the same block, we call that a **polka**.
|
||||||
Every pre-commit must be justified by a polka in the same round.
|
Every pre-commit must be justified by a polka in the same round.
|
||||||
|
|
||||||
Validators may fail to commit a block for a number of reasons;
|
Validators may fail to commit a block for a number of reasons;
|
||||||
|
@ -204,8 +204,8 @@ However, the rest of the protocol is asynchronous, and validators only make prog
|
||||||
A simplifying element of Tendermint is that it uses the same mechanism to commit a block as it does to skip to the next round.
|
A simplifying element of Tendermint is that it uses the same mechanism to commit a block as it does to skip to the next round.
|
||||||
|
|
||||||
Assuming less than one-third of the validators are Byzantine, Tendermint guarantees that safety will never be violated - that is, validators will never commit conflicting blocks at the same height.
|
Assuming less than one-third of the validators are Byzantine, Tendermint guarantees that safety will never be violated - that is, validators will never commit conflicting blocks at the same height.
|
||||||
To do this it introduces a few "locking" rules which modulate which paths can be followed in the flow diagram.
|
To do this it 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.
|
Once a validator precommits a block, it is locked on that block.
|
||||||
Then,
|
Then,
|
||||||
|
|
||||||
1) it must prevote for the block it is locked on
|
1) it must prevote for the block it is locked on
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Genesis
|
Genesis
|
||||||
=======
|
=======
|
||||||
|
|
||||||
The genesis.json file in ``$TMROOT`` defines the initial TendermintCore
|
The genesis.json file in ``$TMHOME`` defines the initial TendermintCore
|
||||||
state upon genesis of the blockchain (`see
|
state upon genesis of the blockchain (`see
|
||||||
definition <https://github.com/tendermint/tendermint/blob/master/types/genesis.go>`__).
|
definition <https://github.com/tendermint/tendermint/blob/master/types/genesis.go>`__).
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ Validators
|
||||||
Validators are responsible for committing new blocks in the blockchain.
|
Validators are responsible for committing new blocks in the blockchain.
|
||||||
These validators participate in the consensus protocol by broadcasting
|
These validators participate in the consensus protocol by broadcasting
|
||||||
*votes* which contain cryptographic signatures signed by each
|
*votes* which contain cryptographic signatures signed by each
|
||||||
validator's public key.
|
validator's private key.
|
||||||
|
|
||||||
Some Proof-of-Stake consensus algorithms aim to create a "completely"
|
Some Proof-of-Stake consensus algorithms aim to create a "completely"
|
||||||
decentralized system where all stakeholders (even those who are not
|
decentralized system where all stakeholders (even those who are not
|
||||||
|
|
|
@ -12,7 +12,7 @@ Directory Root
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The default directory for blockchain data is ``~/.tendermint``. Override
|
The default directory for blockchain data is ``~/.tendermint``. Override
|
||||||
this by setting the ``TMROOT`` environment variable.
|
this by setting the ``TMHOME`` environment variable.
|
||||||
|
|
||||||
Initialize
|
Initialize
|
||||||
----------
|
----------
|
||||||
|
@ -39,7 +39,7 @@ To run a tendermint node, use
|
||||||
|
|
||||||
tendermint node
|
tendermint node
|
||||||
|
|
||||||
By default, Tendermint will try to connect to a abci appliction on
|
By default, Tendermint will try to connect to an ABCI application on
|
||||||
`127.0.0.1:46658 <127.0.0.1:46658>`__. If you have the ``dummy`` ABCI
|
`127.0.0.1:46658 <127.0.0.1:46658>`__. If you have the ``dummy`` ABCI
|
||||||
app installed, run it in another window. If you don't, kill tendermint
|
app installed, run it in another window. If you don't, kill tendermint
|
||||||
and run an in-process version with
|
and run an in-process version with
|
||||||
|
@ -49,9 +49,7 @@ and run an in-process version with
|
||||||
tendermint node --proxy_app=dummy
|
tendermint node --proxy_app=dummy
|
||||||
|
|
||||||
After a few seconds you should see blocks start streaming in. Note that
|
After a few seconds you should see blocks start streaming in. Note that
|
||||||
blocks are produced regularly, even if there are no transactions. This
|
blocks are produced regularly, even if there are no transactions. See *No Empty Blocks*, below, to modify this setting.
|
||||||
changes `with this pull
|
|
||||||
request <https://github.com/tendermint/tendermint/pull/584>`__.
|
|
||||||
|
|
||||||
Tendermint supports in-process versions of the dummy, counter, and nil
|
Tendermint supports in-process versions of the dummy, counter, and nil
|
||||||
apps that ship as examples in the `ABCI
|
apps that ship as examples in the `ABCI
|
||||||
|
@ -59,7 +57,7 @@ repository <https://github.com/tendermint/abci>`__. It's easy to compile
|
||||||
your own app in-process with tendermint if it's written in Go. If your
|
your own app in-process with tendermint if it's written in Go. If your
|
||||||
app is not written in Go, simply run it in another process, and use the
|
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
|
``--proxy_app`` flag to specify the address of the socket it is
|
||||||
listening on, for instance
|
listening on, for instance:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
@ -117,7 +115,7 @@ Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Tendermint uses a ``config.toml`` for configuration. For details, see
|
Tendermint uses a ``config.toml`` for configuration. For details, see
|
||||||
`the documentation <./specification/configuration.html>`__.
|
`the config specification <./specification/configuration.html>`__.
|
||||||
|
|
||||||
Notable options include the socket address of the application
|
Notable options include the socket address of the application
|
||||||
(``proxy_app``), the listenting address of the tendermint peer
|
(``proxy_app``), the listenting address of the tendermint peer
|
||||||
|
@ -283,7 +281,7 @@ specify peers for a running node to connect to:
|
||||||
|
|
||||||
Additionally, the peer-exchange protocol can be enabled using the
|
Additionally, the peer-exchange protocol can be enabled using the
|
||||||
``--pex`` flag, though this feature is `still under
|
``--pex`` flag, though this feature is `still under
|
||||||
development <https://github.com/tendermint/tendermint/issues/598>`__ If
|
development <https://github.com/tendermint/tendermint/issues/598>`__. If
|
||||||
``--pex`` is enabled, peers will gossip about known peers and form a
|
``--pex`` is enabled, peers will gossip about known peers and form a
|
||||||
more resilient network.
|
more resilient network.
|
||||||
|
|
||||||
|
@ -386,3 +384,11 @@ the listening addresses of the various sockets don't conflict.
|
||||||
Additionally, you must set ``addrbook_strict=false`` in the
|
Additionally, you must set ``addrbook_strict=false`` in the
|
||||||
``config.toml``, otherwise Tendermint's p2p library will deny making
|
``config.toml``, otherwise Tendermint's p2p library will deny making
|
||||||
connections to peers with the same IP address.
|
connections to peers with the same IP address.
|
||||||
|
|
||||||
|
Upgrading
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
The tendermint development cycle includes a lot of breaking changes. Upgrading from
|
||||||
|
an old version to a new version usually means throwing away the chain data. Try out
|
||||||
|
the `tm-migrate <https://github.com/hxzqlh/tm-tools>`__ tool written by @hxqlh if
|
||||||
|
you are keen to preserve the state of your chain when upgrading to newer versions.
|
||||||
|
|
|
@ -169,7 +169,7 @@ type Header struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the hash of the header.
|
// Hash returns the hash of the header.
|
||||||
// NOTE: hash is nil if required fields are missing.
|
// Returns nil if ValidatorHash is missing.
|
||||||
func (h *Header) Hash() data.Bytes {
|
func (h *Header) Hash() data.Bytes {
|
||||||
if len(h.ValidatorsHash) == 0 {
|
if len(h.ValidatorsHash) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in New Issue