mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-15 01:02:50 +00:00
Compare commits
4 Commits
main_backu
...
lasarojc-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
131c43af4d | ||
|
|
22d7c37b95 | ||
|
|
afc94526a1 | ||
|
|
ba471248da |
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user