Skip to content

Commit 5d26272

Browse files
authored
docs: add consensus basic notes (#14)
* Add consensus basic notes * Complete consensus doc, add fork-choice (missing slashings) and finality * Add slashing * Added Issue #21 to improve the consensus general doc.
1 parent 3f203b9 commit 5d26272

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

docs/consensus.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Consensus basics
2+
3+
## Classic consensus
4+
5+
As a distributed state machine, the EVM takes some elements from classic consensus algorithms, such as [Raft](https://raft.github.io/):
6+
7+
- Users of the network send commands (transactions) to change the state of the EVM.
8+
- Nodes propagate those transactions.
9+
- A leader is elected and proposes a transaction to be the next one to be applied.
10+
- As there's a single leader, each node will receive that transaction and add it to its local copy of the transaction history.
11+
- Mechanisms are put in place so that nodes make sure that they have the same order of transactions and applying them to their local state machines is safe.
12+
13+
Algorithms like Raft assume a setup where nodes are known, running the same software, well intentioned, and the only problems arise from network/connectivity issues, which are inherent to any distributed system. They prioritize safety and require 50% of the network plus one node to be live in order to be available.
14+
15+
## Bizantine consensus
16+
17+
Blockchains like Ethereum work in a bizantine environment, where anyone can join the network running a software that may be different, due to bugs or intentionally. This means there are several fundamental differences:
18+
19+
- Cryptographic signatures are introduced to validate authority of transactions.
20+
- Transactions are batched into blocks, so that the consensus overhead is reduced.
21+
- Verifying the integrity of blocks needs to be easy. For this reason each block is linked to its parent, each block has a hash of its own contents, and part of each block's content is its parent hash. That means that changing any block in history will cause noticeable changes in the block's hash.
22+
- Leaders are not elected by a simple majority, but by algorithms such as proof of work or proof of stake, that introduce economic incentives so that participating in consensus is not cost-free and chances of spamming the protocol are reduced. They are only elected for a single block and the algorithm is repeated for the next one.
23+
24+
## Forks
25+
26+
In Ethereum, liveness is prioritized over safety, by allowing forks: different versions of history can be live at the same time. Due to networking delays (e.g. block production being faster than propagation) or client differences, a client may receive two different blocks at the same time as the next one.
27+
28+
```mermaid
29+
graph LR
30+
Genesis --> A
31+
Genesis --> B
32+
A --> C
33+
A --> D
34+
```
35+
36+
This means that instead of a block chain we get a block tree, were each branch is called a "fork". Consensus, in this context, means nodes need to chose the same forks as the canonical chain, so that they share the same history. The criteria to chose from a particular fork is called "Fork-choice algorithm".
37+
38+
```mermaid
39+
graph LR
40+
Genesis --> A
41+
Genesis --> B
42+
A --> C
43+
A --> D
44+
45+
classDef chosen fill: #666666
46+
class Genesis chosen
47+
class A chosen
48+
class D chosen
49+
```
50+
51+
Genesis will always be chosen as it will be the first block in any chain. Afterwards, if blocks A and D are chose by the algorithm, that means the canonical chain will now be:
52+
53+
```mermaid
54+
graph LR
55+
Genesis --> A --> D
56+
```
57+
58+
## Ethereum consensus algorithms
59+
60+
In post-merge Ethereum, consensus is reached by two combined fork-related algorithms:
61+
62+
- LMD GHOST: a fork-choice algorithm based on votes (attestations). If a majority of nodes follow this algorithm, they will tend to converge to the same canonical chain. We expand more on it on [this document](fork_choice.md).
63+
- Casper FFG: provides some level of safety by defining a finalization criterion. It takes a fork tree and defines a strategy to prune it (make branches inaccessible). Once a block is tagged as "final", blocks that aren't either parents (which are also final) or decendents of it, are not valid blocks. This prevents long reorganizations, which might make users vulnerable to double spends. We expand on it in [this document](finality.md).
64+
65+
### Attestation messages
66+
67+
A single vote emitted by a validator consists of the following information:
68+
69+
- slot at which the attestation is being emmited.
70+
- index: index of the validator within the comittee.
71+
- beacon block root: the actual vote. This identifies a block by the merkle root of its beacon state.
72+
- source: checkpoint
73+
- target: checkpoint
74+
75+
This messages are propagated either directly (attestation gossip) or indirectly (contained in blocks).

docs/finality.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Finalization: Casper FFG
2+
3+
The name stands for Friendly Finality Gadget. It as a "finality gadget" as it always works on top of a block-proposing algorithm.
4+
5+
**This document will be expaned in a different PR**

docs/fork_choice.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Fork-choice: LMD GHOST
2+
3+
Let's separate the two parts of the name.
4+
5+
- GHOST: **G**reediest, **H**eaviest-**O**bserved **S**ub-**T**ree. The algorithm provides a strategy to choose between two forks/branches. Each branch points to a block, and each block can be thought of as the root of a subtree containing all of its child nodes. The weight of the subtree is the sum of the weights of all blocks in it. The weight of each individual block is obtained from the attestations on them.
6+
- LMD: each validator gives attestations/votes to the block they think is the current head of the chain (Message Driven). "Latest" means that only the last attestation for each validator will be taken into account.
7+
8+
By choosing a fork, each node has a single, linear chain of blocks that it considers canonical. The last child of that chain is called the chain's "head".
9+
10+
## Reacting to an attestation
11+
12+
When an attestation arrives, the `on_attestation` callback must:
13+
14+
1. Perform the [validity checks](https://eth2book.info/capella/part3/forkchoice/phase0/#validate_on_attestation). tl;dr: the slot and epoch need to be right, the vote must be for a block we have, validate the signature and check it doesn't conflict with a different attestation by the same validator.
15+
2. [Save the attestation](https://eth2book.info/capella/part3/forkchoice/phase0/#update_latest_messages) as that validator's latest message. If there's one already, update the value.
16+
17+
## Choosing forks
18+
19+
We now have a store of each validator's latest vote, which allows LMD GHOST to work as a `get_head(store) -> Block` function.
20+
21+
We first need to calculate each block's weight:
22+
23+
- For leaf blocks, we calculate their weight by checking how many votes they have.
24+
- For each branch block we calculate its weight as the sum of the weight of every child, plus its own votes. We repeat this until we reach the root, which will be the last finalized block (there won't be any branches before, so there won't be any more fork-choice to perform).
25+
26+
This way we calculate the weight not only for each block, but for the subtree where that block is the root.
27+
28+
Afterwards, when we want to determine which is the head of the chain, we traverse the tree, starting from the root, and greedily (without looking further ahead) we go block by block chosing the sub-tree with the highest weight.
29+
30+
Let's look at an example:
31+
32+
```mermaid
33+
graph LR
34+
35+
Genesis --> A[A\nb=10\nw=50]
36+
Genesis --> B[B\nb=20\nw=20]
37+
A --> C[C\nb=15\nw=15]
38+
A --> D[D\nb=25\nw=25]
39+
40+
classDef chosen fill: #666666
41+
class Genesis chosen
42+
class A chosen
43+
class D chosen
44+
```
45+
46+
Here, individual block weights are represented by "b", while subtree weights are represented by "w". Some observations:
47+
48+
- $W = B$ for all leaf blocks, as leafs are their own whole subtree.
49+
- $W_A=W_C+W_B +B_A= B_B + B_C + B_A$
50+
- While the individual weight of $A$ is smaller than $B$, its children make the $A$ subtree heavier than the $B$ subtree, so its chosen by LMD GHOST over $B$.
51+
52+
In general:
53+
54+
$$W_N = B_N + \sum_i^{i \in \text{children}[N]}W_i$$
55+
56+
## Slashing
57+
58+
In the previous scheme, there are two rewards:
59+
60+
- Proposer rewards, given to a proposer when their block is included in the chain. This also adds an incentive for them to try to predict the most-likely branch to be the canonical one.
61+
- Attester rewards, which are smaller. These are given if the blocks they attest to are included.
62+
63+
These incentives, however, are not enough. To maximize their likelihood of getting rewards, they may misbehave:
64+
65+
- Proposers may propose a block for every current fork.
66+
- Attesters may attest to every current head in their local chains.
67+
68+
These misbehaviors debilitate the protocol (they give weight to all forks) and no honest node running fork-choice would take part on them. To prevent them, nodes that are detected while doing them are slashed (punished), which means that they are excluded from the validator set and a portion of their stake is burned.
69+
70+
Nodes provide proofs of the offenses, and proposers including them in blocks get whistleblower rewards. Proofs are:
71+
72+
- For proposer slashing: two block headers in the same slot signed by the same signature.
73+
- For attester slashing: two attestations signed in the same slot by the same signature.
74+
75+
## Guarantees
76+
77+
- Majority honest progress: if the network has over 50% nodes running this algorithm honestly, the chain progresses and each older block is exponentially more unlikely to be reverted.
78+
- Stability: fork-choice is self-reinforcing and acts as a good predictor of the next block.
79+
- Manipulation resistence. Not only is it hard to build a secret chain and propose it, but it prevents getting attestations for it, so the current canonical one is always more likely to be heavier. This holds even if the length of the secret chain is higher.

0 commit comments

Comments
 (0)