You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
17 KiB

7 years ago
7 years ago
6 years ago
7 years ago
7 years ago
7 years ago
6 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
6 years ago
7 years ago
6 years ago
7 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
6 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
7 years ago
6 years ago
6 years ago
7 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. ---
  2. order: 4
  3. ---
  4. # Application Development Guide
  5. ## XXX
  6. This page is undergoing deprecation. All content is being moved to the new [home
  7. of the ABCI specification](https://github.com/tendermint/spec/tree/master/spec/abci).
  8. ## ABCI Design
  9. The purpose of ABCI is to provide a clean interface between state
  10. transition machines on one computer and the mechanics of their
  11. replication across multiple computers. The former we call 'application
  12. logic' and the latter the 'consensus engine'. Application logic
  13. validates transactions and optionally executes transactions against some
  14. persistent state. A consensus engine ensures all transactions are
  15. replicated in the same order on every machine. We call each machine in a
  16. consensus engine a 'validator', and each validator runs the same
  17. transactions through the same application logic. In particular, we are
  18. interested in blockchain-style consensus engines, where transactions are
  19. committed in hash-linked blocks.
  20. The ABCI design has a few distinct components:
  21. - message protocol
  22. - pairs of request and response messages
  23. - consensus makes requests, application responds
  24. - defined using protobuf
  25. - server/client
  26. - consensus engine runs the client
  27. - application runs the server
  28. - two implementations:
  29. - async raw bytes
  30. - grpc
  31. - blockchain protocol
  32. - abci is connection oriented
  33. - Tendermint Core maintains three connections:
  34. - [mempool connection](#mempool-connection): for checking if
  35. transactions should be relayed before they are committed;
  36. only uses `CheckTx`
  37. - [consensus connection](#consensus-connection): for executing
  38. transactions that have been committed. Message sequence is
  39. -for every block -`BeginBlock, [DeliverTx, ...], EndBlock, Commit`
  40. - [query connection](#query-connection): for querying the
  41. application state; only uses Query and Info
  42. The mempool and consensus logic act as clients, and each maintains an
  43. open ABCI connection with the application, which hosts an ABCI server.
  44. Shown are the request and response types sent on each connection.
  45. Most of the examples below are from [kvstore
  46. application](https://github.com/tendermint/tendermint/blob/master/abci/example/kvstore/kvstore.go),
  47. which is a part of the abci repo. [persistent_kvstore
  48. application](https://github.com/tendermint/tendermint/blob/master/abci/example/kvstore/persistent_kvstore.go)
  49. is used to show `BeginBlock`, `EndBlock` and `InitChain` example
  50. implementations.
  51. ## Blockchain Protocol
  52. In ABCI, a transaction is simply an arbitrary length byte-array. It is
  53. the application's responsibility to define the transaction codec as they
  54. please, and to use it for both CheckTx and DeliverTx.
  55. Note that there are two distinct means for running transactions,
  56. corresponding to stages of 'awareness' of the transaction in the
  57. network. The first stage is when a transaction is received by a
  58. validator from a client into the so-called mempool or transaction pool
  59. -this is where we use CheckTx. The second is when the transaction is
  60. successfully committed on more than 2/3 of validators - where we use
  61. DeliverTx. In the former case, it may not be necessary to run all the
  62. state transitions associated with the transaction, as the transaction
  63. may not ultimately be committed until some much later time, when the
  64. result of its execution will be different. For instance, an Ethereum
  65. ABCI app would check signatures and amounts in CheckTx, but would not
  66. actually execute any contract code until the DeliverTx, so as to avoid
  67. executing state transitions that have not been finalized.
  68. To formalize the distinction further, two explicit ABCI connections are
  69. made between Tendermint Core and the application: the mempool connection
  70. and the consensus connection. We also make a third connection, the query
  71. connection, to query the local state of the app.
  72. ### Mempool Connection
  73. The mempool connection is used _only_ for CheckTx requests. Transactions
  74. are run using CheckTx in the same order they were received by the
  75. validator. If the CheckTx returns `OK`, the transaction is kept in
  76. memory and relayed to other peers in the same order it was received.
  77. Otherwise, it is discarded.
  78. CheckTx requests run concurrently with block processing; so they should
  79. run against a copy of the main application state which is reset after
  80. every block. This copy is necessary to track transitions made by a
  81. sequence of CheckTx requests before they are included in a block. When a
  82. block is committed, the application must ensure to reset the mempool
  83. state to the latest committed state. Tendermint Core will then filter
  84. through all transactions in the mempool, removing any that were included
  85. in the block, and re-run the rest using CheckTx against the post-Commit
  86. mempool state (this behaviour can be turned off with
  87. `[mempool] recheck = false`).
  88. In go:
  89. ```
  90. func (app *KVStoreApplication) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx {
  91. return types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}
  92. }
  93. ```
  94. In Java:
  95. ```
  96. ResponseCheckTx requestCheckTx(RequestCheckTx req) {
  97. byte[] transaction = req.getTx().toByteArray();
  98. // validate transaction
  99. if (notValid) {
  100. return ResponseCheckTx.newBuilder().setCode(CodeType.BadNonce).setLog("invalid tx").build();
  101. } else {
  102. return ResponseCheckTx.newBuilder().setCode(CodeType.OK).build();
  103. }
  104. }
  105. ```
  106. ### Replay Protection
  107. To prevent old transactions from being replayed, CheckTx must implement
  108. replay protection.
  109. Tendermint provides the first defence layer by keeping a lightweight
  110. in-memory cache of 100k (`[mempool] cache_size`) last transactions in
  111. the mempool. If Tendermint is just started or the clients sent more than
  112. 100k transactions, old transactions may be sent to the application. So
  113. it is important CheckTx implements some logic to handle them.
  114. If there are cases in your application where a transaction may become invalid in some
  115. future state, you probably want to disable Tendermint's
  116. cache. You can do that by setting `[mempool] cache_size = 0` in the
  117. config.
  118. ### Consensus Connection
  119. The consensus connection is used only when a new block is committed, and
  120. communicates all information from the block in a series of requests:
  121. `BeginBlock, [DeliverTx, ...], EndBlock, Commit`. That is, when a block
  122. is committed in the consensus, we send a list of DeliverTx requests (one
  123. for each transaction) sandwiched by BeginBlock and EndBlock requests,
  124. and followed by a Commit.
  125. ### DeliverTx
  126. DeliverTx is the workhorse of the blockchain. Tendermint sends the
  127. DeliverTx requests asynchronously but in order, and relies on the
  128. underlying socket protocol (ie. TCP) to ensure they are received by the
  129. app in order. They have already been ordered in the global consensus by
  130. the Tendermint protocol.
  131. DeliverTx returns a abci.Result, which includes a Code, Data, and Log.
  132. The code may be non-zero (non-OK), meaning the corresponding transaction
  133. should have been rejected by the mempool, but may have been included in
  134. a block by a Byzantine proposer.
  135. The block header will be updated (TODO) to include some commitment to
  136. the results of DeliverTx, be it a bitarray of non-OK transactions, or a
  137. merkle root of the data returned by the DeliverTx requests, or both.
  138. In go:
  139. ```
  140. // tx is either "key=value" or just arbitrary bytes
  141. func (app *KVStoreApplication) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx {
  142. var key, value []byte
  143. parts := bytes.Split(req.Tx, []byte("="))
  144. if len(parts) == 2 {
  145. key, value = parts[0], parts[1]
  146. } else {
  147. key, value = req.Tx, req.Tx
  148. }
  149. app.state.db.Set(prefixKey(key), value)
  150. app.state.Size += 1
  151. events := []types.Event{
  152. {
  153. Type: "app",
  154. Attributes: []kv.Pair{
  155. {Key: []byte("creator"), Value: []byte("Cosmoshi Netowoko")},
  156. {Key: []byte("key"), Value: key},
  157. },
  158. },
  159. }
  160. return types.ResponseDeliverTx{Code: code.CodeTypeOK, Events: events}
  161. }
  162. ```
  163. In Java:
  164. ```
  165. /**
  166. * Using Protobuf types from the protoc compiler, we always start with a byte[]
  167. */
  168. ResponseDeliverTx deliverTx(RequestDeliverTx request) {
  169. byte[] transaction = request.getTx().toByteArray();
  170. // validate your transaction
  171. if (notValid) {
  172. return ResponseDeliverTx.newBuilder().setCode(CodeType.BadNonce).setLog("transaction was invalid").build();
  173. } else {
  174. ResponseDeliverTx.newBuilder().setCode(CodeType.OK).build();
  175. }
  176. }
  177. ```
  178. ### Commit
  179. Once all processing of the block is complete, Tendermint sends the
  180. Commit request and blocks waiting for a response. While the mempool may
  181. run concurrently with block processing (the BeginBlock, DeliverTxs, and
  182. EndBlock), it is locked for the Commit request so that its state can be
  183. safely updated during Commit. This means the app _MUST NOT_ do any
  184. blocking communication with the mempool (ie. broadcast_tx) during
  185. Commit, or there will be deadlock. Note also that all remaining
  186. transactions in the mempool are replayed on the mempool connection
  187. (CheckTx) following a commit.
  188. The app should respond to the Commit request with a byte array, which is
  189. the deterministic state root of the application. It is included in the
  190. header of the next block. It can be used to provide easily verified
  191. Merkle-proofs of the state of the application.
  192. It is expected that the app will persist state to disk on Commit. The
  193. option to have all transactions replayed from some previous block is the
  194. job of the [Handshake](#handshake).
  195. In go:
  196. ```
  197. func (app *KVStoreApplication) Commit() types.ResponseCommit {
  198. // Using a memdb - just return the big endian size of the db
  199. appHash := make([]byte, 8)
  200. binary.PutVarint(appHash, app.state.Size)
  201. app.state.AppHash = appHash
  202. app.state.Height += 1
  203. saveState(app.state)
  204. return types.ResponseCommit{Data: appHash}
  205. }
  206. ```
  207. In Java:
  208. ```
  209. ResponseCommit requestCommit(RequestCommit requestCommit) {
  210. // update the internal app-state
  211. byte[] newAppState = calculateAppState();
  212. // and return it to the node
  213. return ResponseCommit.newBuilder().setCode(CodeType.OK).setData(ByteString.copyFrom(newAppState)).build();
  214. }
  215. ```
  216. ### BeginBlock
  217. The BeginBlock request can be used to run some code at the beginning of
  218. every block. It also allows Tendermint to send the current block hash
  219. and header to the application, before it sends any of the transactions.
  220. The app should remember the latest height and header (ie. from which it
  221. has run a successful Commit) so that it can tell Tendermint where to
  222. pick up from when it restarts. See information on the Handshake, below.
  223. In go:
  224. ```
  225. // Track the block hash and header information
  226. func (app *PersistentKVStoreApplication) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock {
  227. // reset valset changes
  228. app.ValUpdates = make([]types.ValidatorUpdate, 0)
  229. return types.ResponseBeginBlock{}
  230. }
  231. ```
  232. In Java:
  233. ```
  234. /*
  235. * all types come from protobuf definition
  236. */
  237. ResponseBeginBlock requestBeginBlock(RequestBeginBlock req) {
  238. Header header = req.getHeader();
  239. byte[] prevAppHash = header.getAppHash().toByteArray();
  240. long prevHeight = header.getHeight();
  241. // run your pre-block logic. Maybe prepare a state snapshot, message components, etc
  242. return ResponseBeginBlock.newBuilder().build();
  243. }
  244. ```
  245. ### EndBlock
  246. The EndBlock request can be used to run some code at the end of every block.
  247. Additionally, the response may contain a list of validators, which can be used
  248. to update the validator set. To add a new validator or update an existing one,
  249. simply include them in the list returned in the EndBlock response. To remove
  250. one, include it in the list with a `power` equal to `0`. Validator's `address`
  251. field can be left empty. Tendermint core will take care of updating the
  252. validator set. Note the change in voting power must be strictly less than 1/3
  253. per block if you want a light client to be able to prove the transition
  254. externally. See the [light client
  255. docs](https://godoc.org/github.com/tendermint/tendermint/lite#hdr-How_We_Track_Validators)
  256. for details on how it tracks validators.
  257. In go:
  258. ```
  259. // Update the validator set
  260. func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock {
  261. return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates}
  262. }
  263. ```
  264. In Java:
  265. ```
  266. /*
  267. * Assume that one validator changes. The new validator has a power of 10
  268. */
  269. ResponseEndBlock requestEndBlock(RequestEndBlock req) {
  270. final long currentHeight = req.getHeight();
  271. final byte[] validatorPubKey = getValPubKey();
  272. ResponseEndBlock.Builder builder = ResponseEndBlock.newBuilder();
  273. builder.addDiffs(1, Types.Validator.newBuilder().setPower(10L).setPubKey(ByteString.copyFrom(validatorPubKey)).build());
  274. return builder.build();
  275. }
  276. ```
  277. ### Query Connection
  278. This connection is used to query the application without engaging
  279. consensus. It's exposed over the tendermint core rpc, so clients can
  280. query the app without exposing a server on the app itself, but they must
  281. serialize each query as a single byte array. Additionally, certain
  282. "standardized" queries may be used to inform local decisions, for
  283. instance about which peers to connect to.
  284. Tendermint Core currently uses the Query connection to filter peers upon
  285. connecting, according to IP address or node ID. For instance,
  286. returning non-OK ABCI response to either of the following queries will
  287. cause Tendermint to not connect to the corresponding peer:
  288. - `p2p/filter/addr/<ip addr>`, where `<ip addr>` is an IP address.
  289. - `p2p/filter/id/<id>`, where `<is>` is the hex-encoded node ID (the hash of
  290. the node's p2p pubkey).
  291. Note: these query formats are subject to change!
  292. In go:
  293. ```
  294. func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
  295. if reqQuery.Prove {
  296. value := app.state.db.Get(prefixKey(reqQuery.Data))
  297. resQuery.Index = -1 // TODO make Proof return index
  298. resQuery.Key = reqQuery.Data
  299. resQuery.Value = value
  300. if value != nil {
  301. resQuery.Log = "exists"
  302. } else {
  303. resQuery.Log = "does not exist"
  304. }
  305. return
  306. } else {
  307. resQuery.Key = reqQuery.Data
  308. value := app.state.db.Get(prefixKey(reqQuery.Data))
  309. resQuery.Value = value
  310. if value != nil {
  311. resQuery.Log = "exists"
  312. } else {
  313. resQuery.Log = "does not exist"
  314. }
  315. return
  316. }
  317. }
  318. ```
  319. In Java:
  320. ```
  321. ResponseQuery requestQuery(RequestQuery req) {
  322. final boolean isProveQuery = req.getProve();
  323. final ResponseQuery.Builder responseBuilder = ResponseQuery.newBuilder();
  324. byte[] queryData = req.getData().toByteArray();
  325. if (isProveQuery) {
  326. com.app.example.QueryResultWithProof result = generateQueryResultWithProof(queryData);
  327. responseBuilder.setIndex(result.getLeftIndex());
  328. responseBuilder.setKey(req.getData());
  329. responseBuilder.setValue(result.getValueOrNull(0));
  330. responseBuilder.setHeight(result.getHeight());
  331. responseBuilder.setProof(result.getProof());
  332. responseBuilder.setLog(result.getLogValue());
  333. } else {
  334. com.app.example.QueryResult result = generateQueryResult(queryData);
  335. responseBuilder.setIndex(result.getIndex());
  336. responseBuilder.setValue(result.getValue());
  337. responseBuilder.setLog(result.getLogValue());
  338. }
  339. responseBuilder.setIndex(result.getIndex());
  340. responseBuilder.setValue(ByteString.copyFrom(result.getValue()));
  341. responseBuilder.setLog(result.getLogValue());
  342. }
  343. return responseBuilder.build();
  344. }
  345. ```
  346. ### Handshake
  347. When the app or tendermint restarts, they need to sync to a common
  348. height. When an ABCI connection is first established, Tendermint will
  349. call `Info` on the Query connection. The response should contain the
  350. LastBlockHeight and LastBlockAppHash - the former is the last block for
  351. which the app ran Commit successfully, the latter is the response from
  352. that Commit.
  353. Using this information, Tendermint will determine what needs to be
  354. replayed, if anything, against the app, to ensure both Tendermint and
  355. the app are synced to the latest block height.
  356. If the app returns a LastBlockHeight of 0, Tendermint will just replay
  357. all blocks.
  358. In go:
  359. ```
  360. func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
  361. return types.ResponseInfo{
  362. Data: fmt.Sprintf("{\"size\":%v}", app.state.Size),
  363. Version: version.ABCIVersion,
  364. AppVersion: ProtocolVersion.Uint64(),
  365. }
  366. }
  367. ```
  368. In Java:
  369. ```
  370. ResponseInfo requestInfo(RequestInfo req) {
  371. final byte[] lastAppHash = getLastAppHash();
  372. final long lastHeight = getLastHeight();
  373. return ResponseInfo.newBuilder().setLastBlockAppHash(ByteString.copyFrom(lastAppHash)).setLastBlockHeight(lastHeight).build();
  374. }
  375. ```
  376. ### Genesis
  377. `InitChain` will be called once upon the genesis. `params` includes the
  378. initial validator set. Later on, it may be extended to take parts of the
  379. consensus params.
  380. In go:
  381. ```
  382. // Save the validators in the merkle tree
  383. func (app *PersistentKVStoreApplication) InitChain(req types.RequestInitChain) types.ResponseInitChain {
  384. for _, v := range req.Validators {
  385. r := app.updateValidator(v)
  386. if r.IsErr() {
  387. app.logger.Error("Error updating validators", "r", r)
  388. }
  389. }
  390. return types.ResponseInitChain{}
  391. }
  392. ```
  393. In Java:
  394. ```
  395. /*
  396. * all types come from protobuf definition
  397. */
  398. ResponseInitChain requestInitChain(RequestInitChain req) {
  399. final int validatorsCount = req.getValidatorsCount();
  400. final List<Types.Validator> validatorsList = req.getValidatorsList();
  401. validatorsList.forEach((validator) -> {
  402. long power = validator.getPower();
  403. byte[] validatorPubKey = validator.getPubKey().toByteArray();
  404. // do somehing for validator setup in app
  405. });
  406. return ResponseInitChain.newBuilder().build();
  407. }
  408. ```