Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Casper Version 1 Implementation Guide
In this proposed spec for stage 1 Casper, Ethereum will transition from pure proof of work to hybrid PoW/PoS. In this scheme, all of the proof of work mechanics will continue to exist, but additional proof of stake mechanics will be added, and the fork choice rule (ie. the way that a client determines which chain is "the canonical chain") will be modified to take these mechanics into account.
A "Casper contract" will be published at some address
CASPER_ADDR, and this contract will include functionality that allows anyone to deposit their ether, specifying a piece of "validation code" (think of this as being kind of like a public key) that they will use to sign messages, and become a validator. Once a user is inducted into the active validator pool, they will be able to send messages to participate in the PoS consensus process. The "size" of a validator in the active validator pool refers to the amount of ether that they deposited.
The purpose of the PoS consensus process is to "finalize" key blocks called "checkpoints". Every 100th block is a checkpoint. In order for a block to be finalized, a subset of validators in the active validator pool with total size of at least two thirds the total size of the active validator pool need to send "commit" messages for that checkpoint. Once a block is finalized, the theory is that "one can never go back"; even if 99% of miners start supporting a chain that does not contain that block, clients will still accept that block as finalized.
The contract implements a set of rules called "slashing conditions"; these rules were carefully designed to have the property that if two incompatible blocks are finalized (eg. A and B are finalized where A and B are both children of C), then no matter how such a situation arises, there MUST exist some set of validators, with total size equal to at least 1/3 of some recent active validator set, which sent messages that trigger some slashing condition. If a validator does this, then "evidence" of this fact can be sent into the Casper contract, and the validator's entire deposit will be destroyed (except 4%, which is given to the evidence submitter as a "finder's fee"). Hence, reverting a finalized block is extremely expensive, likely more expensive than the cost of buying enough mining hardware to repeatedly engage in 51% attacks against the current PoW-only Ethereum chain forever.
There are two parts to the implementation of a stage-1-Casper-friendly Ethereum implementation:
- An implementation of the "fork choice rule", the function which determines what the "canonical chain" is. This is the replacement for the "longest chain rule" in PoW.
- A daemon (or integrated software package) that implements the logic needed to be a Casper validator.
Fork choice rule
For every checkpoint, maintain the following data:
parent: the parent checkpoint (ie. the 100th ancestor)
commit_frac: the percentage of validators that have committed (or, more precisely, the output of
get_main_hash_committed_frac(), bounded above by 2/3)
pow_head: the block which is a descendant of the checkpoint, and is in the same epoch as the checkpoint (ie. is at most a 99th degree descendant), with the highest total difficulty
max_td: the total difficulty of the
score = commit_frac + epsilon * max_td
subtree_score: the highest
scoreof either this checkpoint or any of its descendants
preferred_child: the child checkpoint with the highest
When you receive a new checkpoint or block, update these records for the checkpoint (for a block, update the
max_td for the checkpoint which is the most recent ancestor of that block). If the block contains prepares or commits, then update
score. Suppose the new
score you calculate is
S. Then, recursively descend to the parent checkpoint, and keep setting
subtree_score = S until you find a checkpoint where
subtree_score >= S; stop there. While descending, update the
preferred_child_subtree_score as needed (that is, if
S > preferred_child_subtree_score, then set
preferred_child to be the child of the current checkpoint you are visiting, and set
preferred_child_subtree_score = S).
With this data saved, you can always walk up
preferred_child pointers from the genesis to find the head. However, this takes O(n) time, so if we want the head immediately accessible we should store the
head_checkpoint (the true head of the chain is
head_checkpoint.pow_head). To keep the
head_checkpoint updated, after the above updating step you can walk back to the common ancestor of the
head and the oldest checkpoint visited, and walk up
preferred_child pointers from there to find the new head.
Validators will need to be able to:
- Store the last epoch they prepared in and the last epoch they committed in, to make sure they do not violate any slashing conditions
- Prepare when needed, using the right epoch as justification
- Commit when needed
- Deposit ether, and detect their validator index
- Withdraw ether
- Broadcast prepare and commit messages, and accept and include into blocks prepare and commit messages from other validators