Casper Version 1 Implementation Guide

Gregory Sanders edited this page Mar 29, 2018 · 5 revisions

Background

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.

Implementation

There are two parts to the implementation of a stage-1-Casper-friendly Ethereum implementation:

  1. 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.
  2. 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 pow_head
  • score = commit_frac + epsilon * max_td
  • subtree_score: the highest score of either this checkpoint or any of its descendants
  • preferred_child: the child checkpoint with the highest subtree_score
  • preferred_child_subtree_score: the subtree_score of the preferred_child

When you receive a new checkpoint or block, update these records for the checkpoint (for a block, update the pow_head and max_td for the checkpoint which is the most recent ancestor of that block). If the block contains prepares or commits, then update commit_frac and 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 and 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.

Validator logic

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
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.