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.

648 lines
23 KiB

  1. Application Development Guide
  2. =============================
  3. ABCI Design
  4. -----------
  5. The purpose of ABCI is to provide a clean interface between state
  6. transition machines on one computer and the mechanics of their
  7. replication across multiple computers. The former we call 'application
  8. logic' and the latter the 'consensus engine'. Application logic
  9. validates transactions and optionally executes transactions against some
  10. persistent state. A consensus engine ensures all transactions are
  11. replicated in the same order on every machine. We call each machine in a
  12. consensus engine a 'validator', and each validator runs the same
  13. transactions through the same application logic. In particular, we are
  14. interested in blockchain-style consensus engines, where transactions are
  15. committed in hash-linked blocks.
  16. The ABCI design has a few distinct components:
  17. - message protocol
  18. - pairs of request and response messages
  19. - consensus makes requests, application responds
  20. - defined using protobuf
  21. - server/client
  22. - consensus engine runs the client
  23. - application runs the server
  24. - two implementations:
  25. - async raw bytes
  26. - grpc
  27. - blockchain protocol
  28. - abci is connection oriented
  29. - Tendermint Core maintains three connections:
  30. - `mempool connection <#mempool-connection>`__: for checking if
  31. transactions should be relayed before they are committed; only
  32. uses ``CheckTx``
  33. - `consensus connection <#consensus-connection>`__: for executing
  34. transactions that have been committed. Message sequence is -
  35. for every block -
  36. ``BeginBlock, [DeliverTx, ...], EndBlock, Commit``
  37. - `query connection <#query-connection>`__: for querying the
  38. application state; only uses Query and Info
  39. The mempool and consensus logic act as clients, and each maintains an
  40. open ABCI connection with the application, which hosts an ABCI server.
  41. Shown are the request and response types sent on each connection.
  42. Message Protocol
  43. ----------------
  44. The message protocol consists of pairs of requests and responses. Some
  45. messages have no fields, while others may include byte-arrays, strings,
  46. or integers. See the ``message Request`` and ``message Response``
  47. definitions in `the protobuf definition
  48. file <https://github.com/tendermint/abci/blob/master/types/types.proto>`__,
  49. and the `protobuf
  50. documentation <https://developers.google.com/protocol-buffers/docs/overview>`__
  51. for more details.
  52. For each request, a server should respond with the corresponding
  53. response, where order of requests is preserved in the order of
  54. responses.
  55. Server
  56. ------
  57. To use ABCI in your programming language of choice, there must be a ABCI
  58. server in that language. Tendermint supports two kinds of implementation
  59. of the server:
  60. - Asynchronous, raw socket server (Tendermint Socket Protocol, also
  61. known as TSP or Teaspoon)
  62. - GRPC
  63. Both can be tested using the ``abci-cli`` by setting the ``--abci`` flag
  64. appropriately (ie. to ``socket`` or ``grpc``).
  65. See examples, in various stages of maintenance, in
  66. `Go <https://github.com/tendermint/abci/tree/master/server>`__,
  67. `JavaScript <https://github.com/tendermint/js-abci>`__,
  68. `Python <https://github.com/tendermint/abci/tree/master/example/python3/abci>`__,
  69. `C++ <https://github.com/mdyring/cpp-tmsp>`__, and
  70. `Java <https://github.com/jTendermint/jabci>`__.
  71. GRPC
  72. ~~~~
  73. If GRPC is available in your language, this is the easiest approach,
  74. though it will have significant performance overhead.
  75. To get started with GRPC, copy in the `protobuf
  76. file <https://github.com/tendermint/abci/blob/master/types/types.proto>`__
  77. and compile it using the GRPC plugin for your language. For instance,
  78. for golang, the command is
  79. ``protoc --go_out=plugins=grpc:. types.proto``. See the `grpc
  80. documentation for more details <http://www.grpc.io/docs/>`__. ``protoc``
  81. will autogenerate all the necessary code for ABCI client and server in
  82. your language, including whatever interface your application must
  83. satisfy to be used by the ABCI server for handling requests.
  84. TSP
  85. ~~~
  86. If GRPC is not available in your language, or you require higher
  87. performance, or otherwise enjoy programming, you may implement your own
  88. ABCI server using the Tendermint Socket Protocol, known affectionately
  89. as Teaspoon. The first step is still to auto-generate the relevant data
  90. types and codec in your language using ``protoc``. Messages coming over
  91. the socket are Protobuf3 encoded, but additionally length-prefixed to
  92. facilitate use as a streaming protocol. Protobuf3 doesn't have an
  93. official length-prefix standard, so we use our own. The first byte in
  94. the prefix represents the length of the Big Endian encoded length. The
  95. remaining bytes in the prefix are the Big Endian encoded length.
  96. For example, if the Protobuf3 encoded ABCI message is 0xDEADBEEF (4
  97. bytes), the length-prefixed message is 0x0104DEADBEEF. If the Protobuf3
  98. encoded ABCI message is 65535 bytes long, the length-prefixed message
  99. would be like 0x02FFFF....
  100. Note this prefixing does not apply for grpc.
  101. An ABCI server must also be able to support multiple connections, as
  102. Tendermint uses three connections.
  103. Client
  104. ------
  105. There are currently two use-cases for an ABCI client. One is a testing
  106. tool, as in the ``abci-cli``, which allows ABCI requests to be sent via
  107. command line. The other is a consensus engine, such as Tendermint Core,
  108. which makes requests to the application every time a new transaction is
  109. received or a block is committed.
  110. It is unlikely that you will need to implement a client. For details of
  111. our client, see
  112. `here <https://github.com/tendermint/abci/tree/master/client>`__.
  113. Most of the examples below are from `kvstore application
  114. <https://github.com/tendermint/abci/blob/master/example/kvstore/kvstore.go>`__,
  115. which is a part of the abci repo. `persistent_kvstore application
  116. <https://github.com/tendermint/abci/blob/master/example/kvstore/persistent_kvstore.go>`__
  117. is used to show ``BeginBlock``, ``EndBlock`` and ``InitChain``
  118. example implementations.
  119. Blockchain Protocol
  120. -------------------
  121. In ABCI, a transaction is simply an arbitrary length byte-array. It is
  122. the application's responsibility to define the transaction codec as they
  123. please, and to use it for both CheckTx and DeliverTx.
  124. Note that there are two distinct means for running transactions,
  125. corresponding to stages of 'awareness' of the transaction in the
  126. network. The first stage is when a transaction is received by a
  127. validator from a client into the so-called mempool or transaction pool -
  128. this is where we use CheckTx. The second is when the transaction is
  129. successfully committed on more than 2/3 of validators - where we use
  130. DeliverTx. In the former case, it may not be necessary to run all the
  131. state transitions associated with the transaction, as the transaction
  132. may not ultimately be committed until some much later time, when the
  133. result of its execution will be different. For instance, an Ethereum
  134. ABCI app would check signatures and amounts in CheckTx, but would not
  135. actually execute any contract code until the DeliverTx, so as to avoid
  136. executing state transitions that have not been finalized.
  137. To formalize the distinction further, two explicit ABCI connections are
  138. made between Tendermint Core and the application: the mempool connection
  139. and the consensus connection. We also make a third connection, the query
  140. connection, to query the local state of the app.
  141. Mempool Connection
  142. ~~~~~~~~~~~~~~~~~~
  143. The mempool connection is used *only* for CheckTx requests.
  144. Transactions are run using CheckTx in the same order they were
  145. received by the validator. If the CheckTx returns ``OK``, the
  146. transaction is kept in memory and relayed to other peers in the same
  147. order it was received. Otherwise, it is discarded.
  148. CheckTx requests run concurrently with block processing; so they
  149. should run against a copy of the main application state which is reset
  150. after every block. This copy is necessary to track transitions made by
  151. a sequence of CheckTx requests before they are included in a block.
  152. When a block is committed, the application must ensure to reset the
  153. mempool state to the latest committed state. Tendermint Core will then
  154. filter through all transactions in the mempool, removing any that were
  155. included in the block, and re-run the rest using CheckTx against the
  156. post-Commit mempool state (this behaviour can be turned off with
  157. ``[mempool] recheck = false``).
  158. .. container:: toggle
  159. .. container:: header
  160. **Show/Hide Go Example**
  161. .. code-block:: go
  162. func (app *KVStoreApplication) CheckTx(tx []byte) types.Result {
  163. return types.OK
  164. }
  165. .. container:: toggle
  166. .. container:: header
  167. **Show/Hide Java Example**
  168. .. code-block:: java
  169. ResponseCheckTx requestCheckTx(RequestCheckTx req) {
  170. byte[] transaction = req.getTx().toByteArray();
  171. // validate transaction
  172. if (notValid) {
  173. return ResponseCheckTx.newBuilder().setCode(CodeType.BadNonce).setLog("invalid tx").build();
  174. } else {
  175. return ResponseCheckTx.newBuilder().setCode(CodeType.OK).build();
  176. }
  177. }
  178. Replay Protection
  179. ^^^^^^^^^^^^^^^^^
  180. To prevent old transactions from being replayed, CheckTx must
  181. implement replay protection.
  182. Tendermint provides the first defence layer by keeping a lightweight
  183. in-memory cache of 100k (``[mempool] cache_size``) last transactions in
  184. the mempool. If Tendermint is just started or the clients sent more
  185. than 100k transactions, old transactions may be sent to the
  186. application. So it is important CheckTx implements some logic to
  187. handle them.
  188. There are cases where a transaction will (or may) become valid in some
  189. future state, in which case you probably want to disable Tendermint's
  190. cache. You can do that by setting ``[mempool] cache_size = 0`` in the
  191. config.
  192. Consensus Connection
  193. ~~~~~~~~~~~~~~~~~~~~
  194. The consensus connection is used only when a new block is committed, and
  195. communicates all information from the block in a series of requests:
  196. ``BeginBlock, [DeliverTx, ...], EndBlock, Commit``. That is, when a
  197. block is committed in the consensus, we send a list of DeliverTx
  198. requests (one for each transaction) sandwiched by BeginBlock and
  199. EndBlock requests, and followed by a Commit.
  200. DeliverTx
  201. ^^^^^^^^^
  202. DeliverTx is the workhorse of the blockchain. Tendermint sends the
  203. DeliverTx requests asynchronously but in order, and relies on the
  204. underlying socket protocol (ie. TCP) to ensure they are received by the
  205. app in order. They have already been ordered in the global consensus by
  206. the Tendermint protocol.
  207. DeliverTx returns a abci.Result, which includes a Code, Data, and Log.
  208. The code may be non-zero (non-OK), meaning the corresponding transaction
  209. should have been rejected by the mempool, but may have been included in
  210. a block by a Byzantine proposer.
  211. The block header will be updated (TODO) to include some commitment to
  212. the results of DeliverTx, be it a bitarray of non-OK transactions, or a
  213. merkle root of the data returned by the DeliverTx requests, or both.
  214. .. container:: toggle
  215. .. container:: header
  216. **Show/Hide Go Example**
  217. .. code-block:: go
  218. // tx is either "key=value" or just arbitrary bytes
  219. func (app *KVStoreApplication) DeliverTx(tx []byte) types.Result {
  220. parts := strings.Split(string(tx), "=")
  221. if len(parts) == 2 {
  222. app.state.Set([]byte(parts[0]), []byte(parts[1]))
  223. } else {
  224. app.state.Set(tx, tx)
  225. }
  226. return types.OK
  227. }
  228. .. container:: toggle
  229. .. container:: header
  230. **Show/Hide Java Example**
  231. .. code-block:: java
  232. /**
  233. * Using Protobuf types from the protoc compiler, we always start with a byte[]
  234. */
  235. ResponseDeliverTx deliverTx(RequestDeliverTx request) {
  236. byte[] transaction = request.getTx().toByteArray();
  237. // validate your transaction
  238. if (notValid) {
  239. return ResponseDeliverTx.newBuilder().setCode(CodeType.BadNonce).setLog("transaction was invalid").build();
  240. } else {
  241. ResponseDeliverTx.newBuilder().setCode(CodeType.OK).build();
  242. }
  243. }
  244. Commit
  245. ^^^^^^
  246. Once all processing of the block is complete, Tendermint sends the
  247. Commit request and blocks waiting for a response. While the mempool may
  248. run concurrently with block processing (the BeginBlock, DeliverTxs, and
  249. EndBlock), it is locked for the Commit request so that its state can be
  250. safely reset during Commit. This means the app *MUST NOT* do any
  251. blocking communication with the mempool (ie. broadcast\_tx) during
  252. Commit, or there will be deadlock. Note also that all remaining
  253. transactions in the mempool are replayed on the mempool connection
  254. (CheckTx) following a commit.
  255. The app should respond to the Commit request with a byte array, which is the deterministic
  256. state root of the application. It is included in the header of the next
  257. block. It can be used to provide easily verified Merkle-proofs of the
  258. state of the application.
  259. It is expected that the app will persist state to disk on Commit. The
  260. option to have all transactions replayed from some previous block is the
  261. job of the `Handshake <#handshake>`__.
  262. .. container:: toggle
  263. .. container:: header
  264. **Show/Hide Go Example**
  265. .. code-block:: go
  266. func (app *KVStoreApplication) Commit() types.Result {
  267. hash := app.state.Hash()
  268. return types.NewResultOK(hash, "")
  269. }
  270. .. container:: toggle
  271. .. container:: header
  272. **Show/Hide Java Example**
  273. .. code-block:: java
  274. ResponseCommit requestCommit(RequestCommit requestCommit) {
  275. // update the internal app-state
  276. byte[] newAppState = calculateAppState();
  277. // and return it to the node
  278. return ResponseCommit.newBuilder().setCode(CodeType.OK).setData(ByteString.copyFrom(newAppState)).build();
  279. }
  280. BeginBlock
  281. ^^^^^^^^^^
  282. The BeginBlock request can be used to run some code at the beginning of
  283. every block. It also allows Tendermint to send the current block hash
  284. and header to the application, before it sends any of the transactions.
  285. The app should remember the latest height and header (ie. from which it
  286. has run a successful Commit) so that it can tell Tendermint where to
  287. pick up from when it restarts. See information on the Handshake, below.
  288. .. container:: toggle
  289. .. container:: header
  290. **Show/Hide Go Example**
  291. .. code-block:: go
  292. // Track the block hash and header information
  293. func (app *PersistentKVStoreApplication) BeginBlock(params types.RequestBeginBlock) {
  294. // update latest block info
  295. app.blockHeader = params.Header
  296. // reset valset changes
  297. app.changes = make([]*types.Validator, 0)
  298. }
  299. .. container:: toggle
  300. .. container:: header
  301. **Show/Hide Java Example**
  302. .. code-block:: java
  303. /*
  304. * all types come from protobuf definition
  305. */
  306. ResponseBeginBlock requestBeginBlock(RequestBeginBlock req) {
  307. Header header = req.getHeader();
  308. byte[] prevAppHash = header.getAppHash().toByteArray();
  309. long prevHeight = header.getHeight();
  310. long numTxs = header.getNumTxs();
  311. // run your pre-block logic. Maybe prepare a state snapshot, message components, etc
  312. return ResponseBeginBlock.newBuilder().build();
  313. }
  314. EndBlock
  315. ^^^^^^^^
  316. The EndBlock request can be used to run some code at the end of every block.
  317. Additionally, the response may contain a list of validators, which can be used
  318. to update the validator set. To add a new validator or update an existing one,
  319. simply include them in the list returned in the EndBlock response. To remove
  320. one, include it in the list with a ``power`` equal to ``0``. Tendermint core
  321. will take care of updating the validator set. Note the change in voting power
  322. must be strictly less than 1/3 per block if you want a light client to be able
  323. to prove the transition externally. See the `light client docs
  324. <https://godoc.org/github.com/tendermint/tendermint/lite#hdr-How_We_Track_Validators>`__
  325. for details on how it tracks validators.
  326. .. container:: toggle
  327. .. container:: header
  328. **Show/Hide Go Example**
  329. .. code-block:: go
  330. // Update the validator set
  331. func (app *PersistentKVStoreApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock {
  332. return types.ResponseEndBlock{ValidatorUpdates: app.ValUpdates}
  333. }
  334. .. container:: toggle
  335. .. container:: header
  336. **Show/Hide Java Example**
  337. .. code-block:: java
  338. /*
  339. * Assume that one validator changes. The new validator has a power of 10
  340. */
  341. ResponseEndBlock requestEndBlock(RequestEndBlock req) {
  342. final long currentHeight = req.getHeight();
  343. final byte[] validatorPubKey = getValPubKey();
  344. ResponseEndBlock.Builder builder = ResponseEndBlock.newBuilder();
  345. builder.addDiffs(1, Types.Validator.newBuilder().setPower(10L).setPubKey(ByteString.copyFrom(validatorPubKey)).build());
  346. return builder.build();
  347. }
  348. Query Connection
  349. ~~~~~~~~~~~~~~~~
  350. This connection is used to query the application without engaging
  351. consensus. It's exposed over the tendermint core rpc, so clients can
  352. query the app without exposing a server on the app itself, but they must
  353. serialize each query as a single byte array. Additionally, certain
  354. "standardized" queries may be used to inform local decisions, for
  355. instance about which peers to connect to.
  356. Tendermint Core currently uses the Query connection to filter peers upon
  357. connecting, according to IP address or public key. For instance,
  358. returning non-OK ABCI response to either of the following queries will
  359. cause Tendermint to not connect to the corresponding peer:
  360. - ``p2p/filter/addr/<addr>``, where ``<addr>`` is an IP address.
  361. - ``p2p/filter/pubkey/<pubkey>``, where ``<pubkey>`` is the hex-encoded
  362. ED25519 key of the node (not it's validator key)
  363. Note: these query formats are subject to change!
  364. .. container:: toggle
  365. .. container:: header
  366. **Show/Hide Go Example**
  367. .. code-block:: go
  368. func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
  369. if reqQuery.Prove {
  370. value, proof, exists := app.state.Proof(reqQuery.Data)
  371. resQuery.Index = -1 // TODO make Proof return index
  372. resQuery.Key = reqQuery.Data
  373. resQuery.Value = value
  374. resQuery.Proof = proof
  375. if exists {
  376. resQuery.Log = "exists"
  377. } else {
  378. resQuery.Log = "does not exist"
  379. }
  380. return
  381. } else {
  382. index, value, exists := app.state.Get(reqQuery.Data)
  383. resQuery.Index = int64(index)
  384. resQuery.Value = value
  385. if exists {
  386. resQuery.Log = "exists"
  387. } else {
  388. resQuery.Log = "does not exist"
  389. }
  390. return
  391. }
  392. }
  393. .. container:: toggle
  394. .. container:: header
  395. **Show/Hide Java Example**
  396. .. code-block:: java
  397. ResponseQuery requestQuery(RequestQuery req) {
  398. final boolean isProveQuery = req.getProve();
  399. final ResponseQuery.Builder responseBuilder = ResponseQuery.newBuilder();
  400. if (isProveQuery) {
  401. com.app.example.ProofResult proofResult = generateProof(req.getData().toByteArray());
  402. final byte[] proofAsByteArray = proofResult.getAsByteArray();
  403. responseBuilder.setProof(ByteString.copyFrom(proofAsByteArray));
  404. responseBuilder.setKey(req.getData());
  405. responseBuilder.setValue(ByteString.copyFrom(proofResult.getData()));
  406. responseBuilder.setLog(result.getLogValue());
  407. } else {
  408. byte[] queryData = req.getData().toByteArray();
  409. final com.app.example.QueryResult result = generateQueryResult(queryData);
  410. responseBuilder.setIndex(result.getIndex());
  411. responseBuilder.setValue(ByteString.copyFrom(result.getValue()));
  412. responseBuilder.setLog(result.getLogValue());
  413. }
  414. return responseBuilder.build();
  415. }
  416. Handshake
  417. ~~~~~~~~~
  418. When the app or tendermint restarts, they need to sync to a common
  419. height. When an ABCI connection is first established, Tendermint will
  420. call ``Info`` on the Query connection. The response should contain the
  421. LastBlockHeight and LastBlockAppHash - the former is the last block for
  422. which the app ran Commit successfully, the latter is the response
  423. from that Commit.
  424. Using this information, Tendermint will determine what needs to be
  425. replayed, if anything, against the app, to ensure both Tendermint and
  426. the app are synced to the latest block height.
  427. If the app returns a LastBlockHeight of 0, Tendermint will just replay
  428. all blocks.
  429. .. container:: toggle
  430. .. container:: header
  431. **Show/Hide Go Example**
  432. .. code-block:: go
  433. func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
  434. return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())}
  435. }
  436. .. container:: toggle
  437. .. container:: header
  438. **Show/Hide Java Example**
  439. .. code-block:: java
  440. ResponseInfo requestInfo(RequestInfo req) {
  441. final byte[] lastAppHash = getLastAppHash();
  442. final long lastHeight = getLastHeight();
  443. return ResponseInfo.newBuilder().setLastBlockAppHash(ByteString.copyFrom(lastAppHash)).setLastBlockHeight(lastHeight).build();
  444. }
  445. Genesis
  446. ~~~~~~~
  447. ``InitChain`` will be called once upon the genesis. ``params`` includes the
  448. initial validator set. Later on, it may be extended to take parts of the
  449. consensus params.
  450. .. container:: toggle
  451. .. container:: header
  452. **Show/Hide Go Example**
  453. .. code-block:: go
  454. // Save the validators in the merkle tree
  455. func (app *PersistentKVStoreApplication) InitChain(params types.RequestInitChain) {
  456. for _, v := range params.Validators {
  457. r := app.updateValidator(v)
  458. if r.IsErr() {
  459. app.logger.Error("Error updating validators", "r", r)
  460. }
  461. }
  462. }
  463. .. container:: toggle
  464. .. container:: header
  465. **Show/Hide Java Example**
  466. .. code-block:: java
  467. /*
  468. * all types come from protobuf definition
  469. */
  470. ResponseInitChain requestInitChain(RequestInitChain req) {
  471. final int validatorsCount = req.getValidatorsCount();
  472. final List<Types.Validator> validatorsList = req.getValidatorsList();
  473. validatorsList.forEach((validator) -> {
  474. long power = validator.getPower();
  475. byte[] validatorPubKey = validator.getPubKey().toByteArray();
  476. // do somehing for validator setup in app
  477. });
  478. return ResponseInitChain.newBuilder().build();
  479. }