Compare commits

...

4 Commits

Author SHA1 Message Date
Lasaro Camargos
131c43af4d Merge branch 'main' into lasarojc-patch-2 2022-11-16 10:42:48 -03:00
Lasaro Camargos
22d7c37b95 Update abci++_app_requirements.md 2022-11-15 10:45:06 -03:00
Lasaro Camargos
afc94526a1 Update abci++_app_requirements.md 2022-11-14 17:52:31 -03:00
Lasaro Camargos
ba471248da Update abci++_app_requirements.md 2022-11-11 15:46:34 -03:00

View File

@@ -45,7 +45,7 @@ transaction list returned by the application will never cause the resulting bloc
limit.
* Requirement 3 [`PrepareProposal`, `ProcessProposal`, coherence]: For any two correct processes *p* and *q*,
if *q*'s Tendermint calls `RequestProcessProposal` on *u<sub>p</sub>*,
if *q*'s Tendermint calls `ProcessProposal` on *u<sub>p</sub>*,
*q*'s Application returns Accept in `ResponseProcessProposal`.
Requirement 3 makes sure that blocks proposed by correct processes *always* pass the correct receiving process's
@@ -59,12 +59,12 @@ target for extensive testing and automated verification.
* Requirement 4 [`ProcessProposal`, determinism-1]: `ProcessProposal` is a (deterministic) function of the current
state and the block that is about to be applied. In other words, for any correct process *p*, and any arbitrary block *u*,
if *p*'s Tendermint calls `RequestProcessProposal` on *u* at height *h*,
if *p*'s Tendermint calls `ProcessProposal` on *u* at height *h*,
then *p*'s Application's acceptance or rejection **exclusively** depends on *u* and *s<sub>p,h-1</sub>*.
* Requirement 5 [`ProcessProposal`, determinism-2]: For any two correct processes *p* and *q*, and any arbitrary
block *u*,
if *p*'s (resp. *q*'s) Tendermint calls `RequestProcessProposal` on *u* at height *h*,
if *p*'s (resp. *q*'s) Tendermint calls `ProcessProposal` on *u* at height *h*,
then *p*'s Application accepts *u* if and only if *q*'s Application accepts *u*.
Note that this requirement follows from Requirement 4 and the Agreement property of consensus.
@@ -127,8 +127,8 @@ Extra care should be put in the implementation of `ExtendVote` and `VerifyVoteEx
As a general rule, `VerifyVoteExtension` SHOULD always accept the vote extension.
-->
* Requirement 9 [*all*, no-side-effects]: *p*'s calls to `RequestPrepareProposal`,
`RequestProcessProposal`,
* Requirement 9 [*all*, no-side-effects]: *p*'s calls to `PrepareProposal`,
`ProcessProposal`,
<!--
`RequestExtendVote`, and `RequestVerifyVoteExtension`
-->
@@ -345,7 +345,7 @@ replay protection mechanism with strong guarantees as part of the logic in `Chec
#### Info/Query Connection
The Info (or Query) Connection should maintain a `QueryState`. This connection has two
purposes: 1) having the application answer the queries Tenderissued receives from users
purposes: 1) having the application answer the queries Tendermint receives from users
(see section [Query](#query)),
and 2) synchronizing Tendermint and the Application at start up time (see
[Crash Recovery](#crash-recovery))
@@ -359,7 +359,7 @@ after the full block has been processed and the state committed to disk.
The Snapshot Connection is used to serve state sync snapshots for other nodes
and/or restore state sync snapshots to a local node being bootstrapped.
Snapshop management is optional: an Application may choose not to implement it.
Snapshot management is optional: an Application may choose not to implement it.
For more information, see Section [State Sync](#state-sync).
@@ -822,15 +822,14 @@ On startup, Tendermint calls the `Info` method on the Info Connection to get the
committed state of the app. The app MUST return information consistent with the
last block it succesfully completed Commit for.
If the app succesfully committed block H, then `last_block_height = H` and `last_block_app_hash = <hash returned by Commit for block H>`. If the app
failed during the Commit of block H, then `last_block_height = H-1` and
If the app succesfully committed block H, then `last_block_height = H` and `last_block_app_hash = <hash returned by Commit for block H>`.
If the app failed during the Commit of block H, then `last_block_height = H-1` and
`last_block_app_hash = <hash returned by Commit for block H-1, which is the hash in the header of block H>`.
We now distinguish three heights, and describe how Tendermint syncs itself with
the app.
We now distinguish three heights, and describe how Tendermint syncs itself with the app.
```md
storeBlockHeight = height of the last block Tendermint saw a commit for
storeBlockHeight = height of the last block Tendermint saw a commit for (decided)
stateBlockHeight = height of the last block for which Tendermint completed all
block processing and saved all ABCI results to disk
appBlockHeight = height of the last block for which ABCI app succesfully
@@ -838,46 +837,56 @@ appBlockHeight = height of the last block for which ABCI app succesfully
```
Note we always have `storeBlockHeight >= stateBlockHeight` and `storeBlockHeight >= appBlockHeight`
In other words, as Tendermint runs, the following sequence of events happen, for each new height:
```
update update update
storeBlockHeight stateBlockHeight appBlockHeight
/ / /
...---(1)----|/----------|-------------...---(3)-----------|/----------(2)-------------|/-----(1)--...
| | StartBlock DeliverTx EndBlock | |
Decision Commit
```
Given this timeline `storeBlockHeight >= stateBlockHeight` and `storeBlockHeight >= appBlockHeight`.
Note also Tendermint never calls Commit on an ABCI app twice for the same height.
The procedure is as follows.
Points (1), (2) or (3) denote some particular conditions:
First, some simple start conditions:
- (1) If `storeBlockHeight == stateBlockHeight && appBlockHeight == storeBlockHeight`,
we crashed at an opportune spot.
If `appBlockHeight == 0`, then call InitChain.
- (2) If `storeBlockHeight == stateBlockHeight && storeBlockHeight > appBlockHeight`,
we completed processing the block, but the app forgot its height.
- (3) If `storeBlockHeight == stateBlockHeight+1`,
we started processing the block but didn't finish.
The recovery procedure depends on the condition found.
It starts by checking for the initial state:
If `appBlockHeight == 0`, then call InitChain.\
If `storeBlockHeight == 0`, we're done.
Now, some sanity checks:
If not completed, the procedure performs some sanity checks:
If `storeBlockHeight < appBlockHeight`, error
If `storeBlockHeight < stateBlockHeight`, panic
If `storeBlockHeight > stateBlockHeight+1`, panic
If `storeBlockHeight < appBlockHeight`, error.\
If `storeBlockHeight < stateBlockHeight`, panic.\
If `storeBlockHeight > stateBlockHeight+1`, panic.
Now, the meat:
Then it proceeds based on the values of the three heights:
If `storeBlockHeight == stateBlockHeight && appBlockHeight < storeBlockHeight`,
replay all blocks in full from `appBlockHeight` to `storeBlockHeight`.
This happens if we completed processing the block, but the app forgot its height.
If `storeBlockHeight == stateBlockHeight && appBlockHeight == storeBlockHeight`, we're done.
This happens if we crashed at an opportune spot.
If `storeBlockHeight == stateBlockHeight+1`
This happens if we started processing the block but didn't finish.
If `appBlockHeight < stateBlockHeight`
replay all blocks in full from `appBlockHeight` to `storeBlockHeight-1`,
and replay the block at `storeBlockHeight` using the WAL.
If `stateBlockHeight > appBlockHeight` (2) then\
replay all blocks in full from `appBlockHeight` to `storeBlockHeight-1`,\
**and** replay the block at `storeBlockHeight` using the WAL.\
This happens if the app forgot the last block it committed.
If `appBlockHeight == stateBlockHeight`,
replay the last block (storeBlockHeight) in full.
If `stateBlockHeight == appBlockHeight`, then
replay the last block (storeBlockHeight) in full.\
This happens if we crashed before the app finished Commit
If `appBlockHeight == storeBlockHeight`
update the state using the saved ABCI responses but dont run the block against the real app.
If `storeBlockHeight == appBlockHeight`\
update the state using the saved ABCI responses but dont run the block against the real app.\
This happens if we crashed after the app finished Commit but before Tendermint saved the state.
### State Sync