Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
s/voter/validator
Browse files Browse the repository at this point in the history
  • Loading branch information
aeyakovenko authored and garious committed Jan 30, 2019
1 parent 3cbbcee commit 5b8e7bf
Showing 1 changed file with 60 additions and 49 deletions.
109 changes: 60 additions & 49 deletions book/src/fork-selection.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Fork Selection

This article describes Solana's *Fork Selection* algorithm based on lockouts. It
attempts to solve the following problems:
This design describes a *Fork Selection* algorithm. It addresses the following
problems:

* Some forks may not end up accepted by the super-majority of the cluster, and
voters need to recover from voting on such forks.
Expand All @@ -23,6 +23,9 @@ History ASICS that are much faster than the rest of the cluster. Consensus
needs to be resistant to attacks that exploit the variability in Proof of
History ASIC speed.

For brevity this design assumes that a single voter with a stake is deployed as
an individual validator in the cluster.

## Time

The Solana cluster generates a source of time via a Verifiable Delay Function we
Expand All @@ -35,38 +38,38 @@ generation](fork-generation.md) and [leader rotation](leader-rotation.md).

## Lockouts

The purpose of the lockout is to force a voter to commit opportunity cost to a
specific fork. Lockouts are measured in slots, and therefor represent a
real-time forced delay that a voter needs to wait before breaking the commitment
to a fork.
The purpose of the lockout is to force a validator to commit opportunity cost to
a specific fork. Lockouts are measured in slots, and therefor represent a
real-time forced delay that a validator needs to wait before breaking the
commitment to a fork.

Voters that violate the lockouts and vote for a diverging fork within the
lockout should be punished. The proposed punishment is to slash the voters stake
if a concurrent vote within a lockout for a non-descendant fork can be proven to
the cluster.
Validators that violate the lockouts and vote for a diverging fork within the
lockout should be punished. The proposed punishment is to slash the validator
stake if a concurrent vote within a lockout for a non-descendant fork can be
proven to the cluster.

## Algorithm

The basic idea to this approach is to stack consensus votes and double lockouts.
Each vote in the stack is a confirmation of a fork. Each confirmed fork is an
ancestor of the fork above it. Each consensus vote has a `lockout` in units of
slots before the validator can submit a vote that does not contain the confirmed
fork as an ancestor.
ancestor of the fork above it. Each vote has a `lockout` in units of slots
before the validator can submit a vote that does not contain the confirmed fork
as an ancestor.

When a vote is added to the stack, the lockouts of all the previous votes in the
stack are doubled (more on this in [Rollback](#Rollback)). With each new vote,
a voter commits the previous votes to an ever-increasing lockout. At 32 votes
we can consider the vote to be at `max lockout` any votes with a lockout equal
to or above `1<<32` are dequeued (FIFO). Dequeuing a vote is the trigger for a
reward. If a vote expires before it is dequeued, it and all the votes above it
are popped (LIFO) from the vote stack. The voter needs to start rebuilding the
stack from that point.
a validator commits the previous votes to an ever-increasing lockout. At 32
votes we can consider the vote to be at `max lockout` any votes with a lockout
equal to or above `1<<32` are dequeued (FIFO). Dequeuing a vote is the trigger
for a reward. If a vote expires before it is dequeued, it and all the votes
above it are popped (LIFO) from the vote stack. The validator needs to start
rebuilding the stack from that point.

### Rollback

Before a vote is pushed to the stack, all the votes leading up to vote with a
lower lock time than the new vote are popped. After rollback lockouts are not
doubled until the voter catches up to the rollback height of votes.
doubled until the validator catches up to the rollback height of votes.

For example, a vote stack with the following state:

Expand Down Expand Up @@ -108,67 +111,73 @@ votes.

### Slashing and Rewards

Voters should be rewarded for selecting the fork that the rest of the cluster
selected as often as possible. This is well-aligned with generating a reward
when the vote stack is full and the oldest vote needs to be dequeued. Thus a
reward should be generated for each successful dequeue.
Validators should be rewarded for selecting the fork that the rest of the
cluster selected as often as possible. This is well-aligned with generating a
reward when the vote stack is full and the oldest vote needs to be dequeued.
Thus a reward should be generated for each successful dequeue.

### Cost of Rollback

Cost of rollback of *fork A* is defined as the cost in terms of lockout time to
the validators to confirm any other fork that does not include *fork A* as an
the validator to confirm any other fork that does not include *fork A* as an
ancestor.

The **Economic Finality** of *fork A* can be calculated as the loss of all the
rewards from rollback of *fork A* and its descendants, plus the opportunity
cost of reward due to the exponentially growing lockout of the votes that have
rewards from rollback of *fork A* and its descendants, plus the opportunity cost
of reward due to the exponentially growing lockout of the votes that have
confirmed *fork A*.

### Thresholds

Each voter can independently set a threshold of cluster commitment to a fork
before that voter commits to a fork. For example, at vote stack index 7, the
lockout is 256 time units. A voter may withhold votes and let votes 0-7 expire
unless the vote at index 7 has at greater than 50% commitment in the cluster.
This allows each voter to independently control how much risk to commit to a
fork. Committing to forks at a higher frequency would allow the voter to earn
more rewards.
Each validator can independently set a threshold of cluster commitment to a fork
before that validator commits to a fork. For example, at vote stack index 7,
the lockout is 256 time units. A validator may withhold votes and let votes 0-7
expire unless the vote at index 7 has at greater than 50% commitment in the
cluster. This allows each validator to independently control how much risk to
commit to a fork. Committing to forks at a higher frequency would allow the
validator to earn more rewards.

### Algorithm parameters

These parameters need to be tuned.
The following parameters need to be tuned:

* Number of votes in the stack before dequeue occurs (32).

* Rate of growth for lockouts in the stack (2x).

* Starting default lockout (2).

* Threshold depth for minimum cluster commitment before committing to the fork
(8).
(8).

* Minimum cluster commitment size at threshold depth (50%+).

### Free Choice

A "Free Choice" is an unenforcible voter action. A voter that maximizes
self-reward over all possible futures should behave in such a way that the
system is stable, and the local greedy choice should result in a greedy choice
over all possible futures. A set of voter that are engaging in choices to
disrupt the protocol should be bound by their stake weight to the denial of
service. Two options exits for voter:
A "Free Choice" is an unenforcible validator action. There is no way for the
protocol to encode and enforce these actions since each validator can modify the
code and adjust the algorithm. A validator that maximizes self-reward over all
possible futures should behave in such a way that the system is stable, and the
local greedy choice should result in a greedy choice over all possible futures.
A set of validator that are engaging in choices to disrupt the protocol should
be bound by their stake weight to the denial of service. Two options exits for
validator:

* a voter can outrun previous voters in virtual generation and submit a
* a validator can outrun previous validator in virtual generation and submit a
concurrent fork

* a voter can withhold a vote to observe multiple forks before voting
* a validator can withhold a vote to observe multiple forks before voting

In both cases, the voters in the cluster have several forks to pick from
In both cases, the validator in the cluster have several forks to pick from
concurrently, even though each fork represents a different height. In both
cases it is impossible for the protocol to detect if the voter behavior is
cases it is impossible for the protocol to detect if the validator behavior is
intentional or not.

### Greedy Choice for Concurrent Forks

When evaluating multiple forks, each voter should use the following rules:
When evaluating multiple forks, each validator should use the following rules:

1. Forks must satisify the *Threshold* rule.
1. Forks must satisfy the *Threshold* rule.

2. Pick the fork that maximizes the total cluster lockout time for all the
ancestor forks.
Expand All @@ -192,8 +201,10 @@ effort to censor them. A fork proposed by this attacker will be available
concurrently with the next available leader. For nodes to pick this fork it
must satisfy the *Greedy Choice* rule.

1. Fork must have equal number of validator votes for the ancestor fork.
1. Fork must have equal number of votes for the ancestor fork.

2. Fork cannot be so far a head as to cause expired votes.

3. Fork must have a greater amount of cluster transaction fees.

This attack is then limited to censoring the previous leaders fees, and
Expand Down

0 comments on commit 5b8e7bf

Please sign in to comment.