From 85370705755705c57fe25f5ea613a7979b519bdb Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Tue, 3 Oct 2017 18:07:20 +0400 Subject: [PATCH 1/4] [docs] restructure sentence [ci skip] --- docs/app-development.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/app-development.rst b/docs/app-development.rst index 011fb0f3..8447d2b2 100644 --- a/docs/app-development.rst +++ b/docs/app-development.rst @@ -228,7 +228,7 @@ Commit, or there will be deadlock. Note also that all remaining transactions in the mempool are replayed on the mempool connection (CheckTx) following a commit. -The Commit response includes a byte array, which is the deterministic +The app should respond with a byte array, which is the deterministic 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 state of the application. From 4a0ae17401b4867686341b3aea53a00b18a31ece Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Tue, 3 Oct 2017 18:07:59 +0400 Subject: [PATCH 2/4] [docs] include examples from the persistent_dummy app [ci skip] --- docs/app-development.rst | 97 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/docs/app-development.rst b/docs/app-development.rst index 8447d2b2..5a5b1b82 100644 --- a/docs/app-development.rst +++ b/docs/app-development.rst @@ -142,6 +142,10 @@ It is unlikely that you will need to implement a client. For details of our client, see `here `__. +All examples below are from `persistent-dummy application +`__, +which is a part of the abci repo. + Blockchain Protocol ------------------- @@ -187,6 +191,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 mempool state. +:: + + func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { + return app.app.CheckTx(tx) + } + Consensus Connection ~~~~~~~~~~~~~~~~~~~~ @@ -215,6 +225,22 @@ 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 merkle root of the data returned by the DeliverTx requests, or both. +:: + + // tx is either "key=value" or just arbitrary bytes + func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result { + // if it starts with "val:", update the validator set + // format is "val:pubkey/power" + if isValidatorTx(tx) { + // update validators in the merkle tree + // and in app.changes + return app.execValidatorTx(tx) + } + + // otherwise, update the key-value store + return app.app.DeliverTx(tx) + } + Commit ^^^^^^ @@ -237,6 +263,24 @@ 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 job of the `Handshake <#handshake>`__. +:: + + func (app *PersistentDummyApplication) Commit() types.Result { + // Save + appHash := app.app.state.Save() + app.logger.Info("Saved state", "root", appHash) + + lastBlock := LastBlockInfo{ + Height: app.blockHeader.Height, + AppHash: appHash, // this hash will be in the next block header + } + + app.logger.Info("Saving block", "height", lastBlock.Height, "root", lastBlock.AppHash) + SaveLastBlock(app.db, lastBlock) + + return types.NewResultOK(appHash, "") + } + BeginBlock ^^^^^^^^^^ @@ -248,6 +292,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 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 ^^^^^^^^ @@ -260,6 +315,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 and up. +:: + + // Update the validator set + func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) { + return types.ResponseEndBlock{Diffs: app.changes} + } + Query Connection ~~~~~~~~~~~~~~~~ @@ -281,6 +343,12 @@ cause Tendermint to not connect to the corresponding peer: Note: these query formats are subject to change! +:: + + func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { + return app.app.Query(reqQuery) + } + Handshake ~~~~~~~~~ @@ -297,3 +365,32 @@ the app are synced to the latest block height. If the app returns a LastBlockHeight of 0, Tendermint will just replay all blocks. + +:: + + func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { + resInfo = app.app.Info(req) + lastBlock := LoadLastBlock(app.db) + resInfo.LastBlockHeight = lastBlock.Height + resInfo.LastBlockAppHash = lastBlock.AppHash + return resInfo + } + +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) + } + } + } From 10f361fcd08001656fed62fbf6863fd12481470b Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 4 Oct 2017 00:03:42 +0400 Subject: [PATCH 3/4] [docs] use persistent_dummy only when needed [ci skip] --- docs/app-development.rst | 81 ++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/docs/app-development.rst b/docs/app-development.rst index 5a5b1b82..84654391 100644 --- a/docs/app-development.rst +++ b/docs/app-development.rst @@ -142,9 +142,12 @@ It is unlikely that you will need to implement a client. For details of our client, see `here `__. -All examples below are from `persistent-dummy application -`__, -which is a part of the abci repo. +Most of the examples below are from `dummy application +`__, +which is a part of the abci repo. `persistent_dummy application +`__ +application is used to show ``BeginBlock``, ``EndBlock`` and ``InitChain`` +example implementations. Blockchain Protocol ------------------- @@ -193,8 +196,8 @@ mempool state. :: - func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { - return app.app.CheckTx(tx) + func (app *DummyApplication) CheckTx(tx []byte) types.Result { + return types.OK } Consensus Connection @@ -228,17 +231,14 @@ merkle root of the data returned by the DeliverTx requests, or both. :: // tx is either "key=value" or just arbitrary bytes - func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result { - // if it starts with "val:", update the validator set - // format is "val:pubkey/power" - if isValidatorTx(tx) { - // update validators in the merkle tree - // and in app.changes - return app.execValidatorTx(tx) + 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) } - - // otherwise, update the key-value store - return app.app.DeliverTx(tx) + return types.OK } Commit @@ -265,20 +265,9 @@ job of the `Handshake <#handshake>`__. :: - func (app *PersistentDummyApplication) Commit() types.Result { - // Save - appHash := app.app.state.Save() - app.logger.Info("Saved state", "root", appHash) - - lastBlock := LastBlockInfo{ - Height: app.blockHeader.Height, - AppHash: appHash, // this hash will be in the next block header - } - - app.logger.Info("Saving block", "height", lastBlock.Height, "root", lastBlock.AppHash) - SaveLastBlock(app.db, lastBlock) - - return types.NewResultOK(appHash, "") + func (app *DummyApplication) Commit() types.Result { + hash := app.state.Hash() + return types.NewResultOK(hash, "") } BeginBlock @@ -345,8 +334,30 @@ Note: these query formats are subject to change! :: - func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { - return app.app.Query(reqQuery) + 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 @@ -368,12 +379,8 @@ all blocks. :: - func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { - resInfo = app.app.Info(req) - lastBlock := LoadLastBlock(app.db) - resInfo.LastBlockHeight = lastBlock.Height - resInfo.LastBlockAppHash = lastBlock.AppHash - return resInfo + func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { + return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())} } Genesis From 65501997518b59de12e35cbc11017aa54d162164 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 3 Oct 2017 23:39:28 -0400 Subject: [PATCH 4/4] [docs] minor fixes from review [ci skip] --- docs/app-development.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/app-development.rst b/docs/app-development.rst index 84654391..770572e1 100644 --- a/docs/app-development.rst +++ b/docs/app-development.rst @@ -146,7 +146,7 @@ Most of the examples below are from `dummy application `__, which is a part of the abci repo. `persistent_dummy application `__ -application is used to show ``BeginBlock``, ``EndBlock`` and ``InitChain`` +is used to show ``BeginBlock``, ``EndBlock`` and ``InitChain`` example implementations. Blockchain Protocol @@ -254,7 +254,7 @@ Commit, or there will be deadlock. Note also that all remaining transactions in the mempool are replayed on the mempool connection (CheckTx) following a commit. -The app should respond with 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 block. It can be used to provide easily verified Merkle-proofs of the state of the application.