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.

166 lines
6.7 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. # Application Blockchain Interface (ABCI)
  2. ABCI is the interface between Tendermint (a state-machine replication engine)
  3. and an application (the actual state machine).
  4. The ABCI message types are defined in a [protobuf
  5. file](https://github.com/tendermint/abci/blob/master/types/types.proto).
  6. For full details on the ABCI message types and protocol, see the [ABCI
  7. specificaiton](https://github.com/tendermint/abci/blob/master/specification.rst).
  8. Be sure to read the specification if you're trying to build an ABCI app!
  9. For additional details on server implementation, see the [ABCI
  10. readme](https://github.com/tendermint/abci#implementation).
  11. Here we provide some more details around the use of ABCI by Tendermint and
  12. clarify common "gotchas".
  13. ## ABCI connections
  14. Tendermint opens 3 ABCI connections to the app: one for Consensus, one for
  15. Mempool, one for Queries.
  16. ## Async vs Sync
  17. The main ABCI server (ie. non-GRPC) provides ordered asynchronous messages.
  18. This is useful for DeliverTx and CheckTx, since it allows Tendermint to forward
  19. transactions to the app before it's finished processing previous ones.
  20. Thus, DeliverTx and CheckTx messages are sent asycnhronously, while all other
  21. messages are sent synchronously.
  22. ## CheckTx and Commit
  23. It is typical to hold three distinct states in an ABCI app: CheckTxState, DeliverTxState,
  24. QueryState. The QueryState contains the latest committed state for a block.
  25. The CheckTxState and DeliverTxState may be updated concurrently with one another.
  26. Before Commit is called, Tendermint locks and flushes the mempool so that no new changes will happen
  27. to CheckTxState. When Commit completes, it unlocks the mempool.
  28. Thus, during Commit, it is safe to reset the QueryState and the CheckTxState to the latest DeliverTxState
  29. (ie. the new state from executing all the txs in the block).
  30. Note, however, that it is not possible to send transactions to Tendermint during Commit - if your app
  31. tries to send a `/broadcast_tx` to Tendermint during Commit, it will deadlock.
  32. ## EndBlock Validator Updates
  33. Updates to the Tendermint validator set can be made by returning `Validator`
  34. objects in the `ResponseBeginBlock`:
  35. ```
  36. message Validator {
  37. bytes pub_key = 1;
  38. int64 power = 2;
  39. }
  40. ```
  41. The `pub_key` is the Amino encoded public key for the validator. For details on
  42. Amino encoded public keys, see the [section of the encoding spec](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography).
  43. For Ed25519 pubkeys, the Amino prefix is always "1624DE6220". For example, the 32-byte Ed25519 pubkey
  44. `76852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85` would be
  45. Amino encoded as
  46. `1624DE622076852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85`
  47. (Note: in old versions of Tendermint (pre-v0.19.0), the pubkey is just prefixed with a
  48. single type byte, so for ED25519 we'd have `pub_key = 0x1 | pub`)
  49. The `power` is the new voting power for the validator, with the
  50. following rules:
  51. - power must be non-negative
  52. - if power is 0, the validator must already exist, and will be removed from the
  53. validator set
  54. - if power is non-0:
  55. - if the validator does not already exist, it will be added to the validator
  56. set with the given power
  57. - if the validator does already exist, its power will be adjusted to the given power
  58. ## Query
  59. Query is a generic message type with lots of flexibility to enable diverse sets
  60. of queries from applications. Tendermint has no requirements from the Query
  61. message for normal operation - that is, the ABCI app developer need not implement Query functionality if they do not wish too.
  62. That said, Tendermint makes a number of queries to support some optional
  63. features. These are:
  64. ### Peer Filtering
  65. When Tendermint connects to a peer, it sends two queries to the ABCI application
  66. using the following paths, with no additional data:
  67. - `/p2p/filter/addr/<IP:PORT>`, where `<IP:PORT>` denote the IP address and
  68. the port of the connection
  69. - `p2p/filter/pubkey/<ID>`, where `<ID>` is the peer node ID (ie. the
  70. pubkey.Address() for the peer's PubKey)
  71. If either of these queries return a non-zero ABCI code, Tendermint will refuse
  72. to connect to the peer.
  73. ## Info and the Handshake/Replay
  74. On startup, Tendermint calls Info on the Query connection to get the latest
  75. committed state of the app. The app MUST return information consistent with the
  76. last block it succesfully completed Commit for.
  77. If the app succesfully committed block H but not H+1, then `last_block_height =
  78. H` and `last_block_app_hash = <hash returned by Commit for block H>`. If the app
  79. failed during the Commit of block H, then `last_block_height = H-1` and
  80. `last_block_app_hash = <hash returned by Commit for block H-1, which is the hash
  81. in the header of block H>`.
  82. We now distinguish three heights, and describe how Tendermint syncs itself with
  83. the app.
  84. ```
  85. storeBlockHeight = height of the last block Tendermint saw a commit for
  86. stateBlockHeight = height of the last block for which Tendermint completed all
  87. block processing and saved all ABCI results to disk
  88. appBlockHeight = height of the last block for which ABCI app succesfully
  89. completely Commit
  90. ```
  91. Note we always have `storeBlockHeight >= stateBlockHeight` and `storeBlockHeight >= appBlockHeight`
  92. Note also we never call Commit on an ABCI app twice for the same height.
  93. The procedure is as follows.
  94. First, some simeple start conditions:
  95. If `appBlockHeight == 0`, then call InitChain.
  96. If `storeBlockHeight == 0`, we're done.
  97. Now, some sanity checks:
  98. If `storeBlockHeight < appBlockHeight`, error
  99. If `storeBlockHeight < stateBlockHeight`, panic
  100. If `storeBlockHeight > stateBlockHeight+1`, panic
  101. Now, the meat:
  102. If `storeBlockHeight == stateBlockHeight && appBlockHeight < storeBlockHeight`,
  103. replay all blocks in full from `appBlockHeight` to `storeBlockHeight`.
  104. This happens if we completed processing the block, but the app forgot its height.
  105. If `storeBlockHeight == stateBlockHeight && appBlockHeight == storeBlockHeight`, we're done
  106. This happens if we crashed at an opportune spot.
  107. If `storeBlockHeight == stateBlockHeight+1`
  108. This happens if we started processing the block but didn't finish.
  109. If `appBlockHeight < stateBlockHeight`
  110. replay all blocks in full from `appBlockHeight` to `storeBlockHeight-1`,
  111. and replay the block at `storeBlockHeight` using the WAL.
  112. This happens if the app forgot the last block it committed.
  113. If `appBlockHeight == stateBlockHeight`,
  114. replay the last block (storeBlockHeight) in full.
  115. This happens if we crashed before the app finished Commit
  116. If appBlockHeight == storeBlockHeight {
  117. update the state using the saved ABCI responses but dont run the block against the real app.
  118. This happens if we crashed after the app finished Commit but before Tendermint saved the state.