Browse Source

Merge pull request #700 from tendermint/695-improve-app-dev-docs

Improve app dev docs
pull/707/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
bbf0228aa7
1 changed files with 105 additions and 1 deletions
  1. +105
    -1
      docs/app-development.rst

+ 105
- 1
docs/app-development.rst View File

@ -142,6 +142,13 @@ It is unlikely that you will need to implement a client. For details of
our client, see our client, see
`here <https://github.com/tendermint/abci/tree/master/client>`__. `here <https://github.com/tendermint/abci/tree/master/client>`__.
Most of the examples below are from `dummy application
<https://github.com/tendermint/abci/blob/master/example/dummy/dummy.go>`__,
which is a part of the abci repo. `persistent_dummy application
<https://github.com/tendermint/abci/blob/master/example/dummy/persistent_dummy.go>`__
is used to show ``BeginBlock``, ``EndBlock`` and ``InitChain``
example implementations.
Blockchain Protocol Blockchain Protocol
------------------- -------------------
@ -187,6 +194,12 @@ 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.
::
func (app *DummyApplication) CheckTx(tx []byte) types.Result {
return types.OK
}
Consensus Connection Consensus Connection
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
@ -215,6 +228,19 @@ 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.
::
// tx is either "key=value" or just arbitrary bytes
func (app *DummyApplication) DeliverTx(tx []byte) types.Result {
parts := strings.Split(string(tx), "=")
if len(parts) == 2 {
app.state.Set([]byte(parts[0]), []byte(parts[1]))
} else {
app.state.Set(tx, tx)
}
return types.OK
}
Commit Commit
^^^^^^ ^^^^^^
@ -228,7 +254,7 @@ Commit, or there will be deadlock. Note also that all remaining
transactions in the mempool are replayed on the mempool connection transactions in the mempool are replayed on the mempool connection
(CheckTx) following a commit. (CheckTx) following a commit.
The Commit response includes a byte array, which is the deterministic
The app should respond to the Commit request with a byte array, which is the deterministic
state root of the application. It is included in the header of the next state root of the application. It is included in the header of the next
block. It can be used to provide easily verified Merkle-proofs of the block. It can be used to provide easily verified Merkle-proofs of the
state of the application. state of the application.
@ -237,6 +263,13 @@ 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>`__.
::
func (app *DummyApplication) Commit() types.Result {
hash := app.state.Hash()
return types.NewResultOK(hash, "")
}
BeginBlock BeginBlock
^^^^^^^^^^ ^^^^^^^^^^
@ -248,6 +281,17 @@ 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.
::
// Track the block hash and header information
func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) {
// update latest block info
app.blockHeader = params.Header
// reset valset changes
app.changes = make([]*types.Validator, 0)
}
EndBlock EndBlock
^^^^^^^^ ^^^^^^^^
@ -260,6 +304,13 @@ 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.
::
// Update the validator set
func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) {
return types.ResponseEndBlock{Diffs: app.changes}
}
Query Connection Query Connection
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
@ -281,6 +332,34 @@ 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!
::
func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
if reqQuery.Prove {
value, proof, exists := app.state.Proof(reqQuery.Data)
resQuery.Index = -1 // TODO make Proof return index
resQuery.Key = reqQuery.Data
resQuery.Value = value
resQuery.Proof = proof
if exists {
resQuery.Log = "exists"
} else {
resQuery.Log = "does not exist"
}
return
} else {
index, value, exists := app.state.Get(reqQuery.Data)
resQuery.Index = int64(index)
resQuery.Value = value
if exists {
resQuery.Log = "exists"
} else {
resQuery.Log = "does not exist"
}
return
}
}
Handshake Handshake
~~~~~~~~~ ~~~~~~~~~
@ -297,3 +376,28 @@ 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.
::
func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())}
}
Genesis
~~~~~~~
``InitChain`` will be called once upon the genesis. ``params`` includes the
initial validator set. Later on, it may be extended to take parts of the
consensus params.
::
// Save the validators in the merkle tree
func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) {
for _, v := range params.Validators {
r := app.updateValidator(v)
if r.IsErr() {
app.logger.Error("Error updating validators", "r", r)
}
}
}

Loading…
Cancel
Save