Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review casper_v2.1.md #1

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 31 additions & 21 deletions sharding/review/casper_v2.1.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Full Casper chain v2.1

## WORK IN PROGRESS!!!!1!!1! by @vbuterin - 20180721 21:48 (UTC+8)
## WORK IN PROGRESS!!!!1!!1!

This is the work-in-progress document describing the specification for the Casper+Sharding chain, version 2.1.

Expand All @@ -11,7 +11,6 @@ The primary source of load on the PoS chain is **attestations**. An attestation
1. It attests to some parent block in the beacon chain
2. It attests to a block hash in a shard (a sufficient number of such attestations create a "cross-link", confirming that shard block into the main chain).


Every shard (e.g. there might be 1024 shards in total) is itself a PoS chain, and the shard chains are where the transactions and accounts will be stored. The cross-links serve to "confirm" segments of the shard chains into the main chain, and are also the primary way through which the different shards will be able to talk to each other.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there might be 1024 shards in total -> there might be 1024 shards initially to imply that the shards may grow?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number of shards is constant within the scope of the mechanism (ie. adding more would require a hard fork). So IMO better to keep the emphasis of "it's 1024, deal with it".


Note that one can also consider a simpler "minimal sharding algorithm" where cross-links are simply hashes of proposed blocks.
Expand Down Expand Up @@ -177,11 +176,13 @@ Block production is significantly different because of the proof of stake mechan

The beacon chain uses the Casper FFG fork choice rule of "favor the chain containing the highest-epoch justified checkpoint". To choose between chains that are all descended from the same justified checkpoint, the chain uses "recursive proximity to justification" to choose a checkpoint, then uses GHOST within an epoch.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: "recursive proximity to justification (RPJ)"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nichebiche


RPJ works as follows. First, start at the latest justified checkpoint. Then, choose the descendant checkpoint that has the most attestations supporting it. Repeat until you get to a checkpoint with no children.
RPJ works as follows. First, start at the latest justified checkpoint. Then, choose the descendant checkpoint that has the most attestations supporting it. Repeat until you get to a checkpoint with no children (in this phase, only checkpoints whose epochs are completed, ie. epoch N where the timeslots for epoch N+1 have already begun, are admissible)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

latest justified checkpoint (LJC)


For example:

![](https://yuml.me/8d100380.png =225x600)
![](https://vitalik.ca/files/8d100380.png =225x600)

From the child chosen by RPJ, use GHOST to find the head of the chain.

## Beacon chain state transition function

Expand Down Expand Up @@ -216,7 +217,7 @@ def get_shuffling(seed, validator_count):
return o
```

The following algorithm is used to split up validators into groups at the start of every epoch, determining at what height they can make attestations and what shard they are making crosslinks for:
Then, an algorithm that we use to split up validators into groups at the start of every epoch, determining at what height they can make attestations and what shard they are making crosslinks for:
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what height -> which slot


```python
def get_cutoffs(validator_count):
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All heights in this helper function are actually slots?

Expand Down Expand Up @@ -246,9 +247,9 @@ def get_cutoffs(validator_count):

# For the validators assigned to each height, split them up
# into committees for different shards. Do not assign the
# last 8 heights in an epoch to any shards.
# last END_EPOCH_GRACE_PERIOD heights in an epoch to any shards.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

END_EPOCH_GRACE_PERIOD should be defined in Constants section.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shard_cutoffs = [0]
for i in range(EPOCH_LENGTH - 8):
for i in range(EPOCH_LENGTH - END_EPOCH_GRACE_PERIOD):
size = height_cutoffs[i+1] - height_cutoffs[i]
shards = (size + STANDARD_COMMITTEE_SIZE - 1) // STANDARD_COMMITTEE_SIZE
pre = shard_cutoffs[-1]
Expand All @@ -260,6 +261,10 @@ def get_cutoffs(validator_count):

This splits up the validator set into groups for each height, and within each height into groups for different shards. Note that if the validator set is too small to support a committee at every height, some heights are simply left "inactive".
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

height -> slot


Here's a depiction of what is going on with reduced parameters for simplicity of exposition:

![](http://vitalik.ca/files/ShuffleAndAssign.png)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

height -> slot


The `current_shuffling` is recalculated at the start of a dynasty transition.

### Per-block processing
Expand All @@ -273,30 +278,31 @@ A block can have 0 or more `AggregateVote` objects, where each `AggregateVote` o
```python
fields = {
'height': 'int16',
'parent': 'hash32',
'parent_hash': 'hash32',
'checkpoint_hash': 'hash32',
'shard_id': 'int16',
'shard_block_hash': 'hash32',
'notary_bitfield': 'bytes',
'attester_bitfield': 'bytes',
'aggregate_sig': ['int256']
}
```

For each one of these votes:

* Verify that `height <= slot_number`
* Verify that `height >= slot_number = slot_number % EPOCH_LENGTH`
* Use `get_cutoffs` above to get the index cutoffs for the heights and the shards. If `height_in_epoch < EPOCH_LENGTH - 8`, verify that `si = (shard_id - next_shard) % SHARD_COUNT` is a valid shard index for that height (ie. check `height_cutoffs[height_in_epoch] <= shard_cutoffs[si] < height_cutoffs[height_in_epoch + 1])`). Otherwise, verify `shard_id == 65535` and `shard_block_hash == 0`.
* Use `get_cutoffs` above to get the index cutoffs for the heights and the shards.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heights -> slots

* If `height_in_epoch < EPOCH_LENGTH - END_EPOCH_GRACE_PERIOD`, verify that `si = (shard_id - next_shard) % SHARD_COUNT` is a valid shard index for that height (ie. check `height_cutoffs[height_in_epoch] <= shard_cutoffs[si] < height_cutoffs[height_in_epoch + 1])`).
* Otherwise, verify `shard_id == 65535` and `shard_block_hash == 0`.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shard_id == 65535 implies that MAX_SHARD_COUNT is 2^16. Why not set MAX_SHARD_COUNTto 2^15, where MAX_VALIDATOR_COUNT / MIN_COMMITTEE_SIZE = 2^15?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is to have an "out of the way" shard ID that doesn't represent any shard.

* If `height_in_epoch < EPOCH_LENGTH - 8`, let `start = shard_cutoffs[si]` and `end = shard_cutoffs[si+1]`. Otherwise, let `start = height_cutoffs[height_in_epoch]` and `end = height_cutoffs[height_in_epoch + 1]`
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should replace 8 with END_EPOCH_GRACE_PERIOD.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* Verify that `len(notary_bitfield) == ceil_div8(end - start)`, where `ceil_div8 = (x + 7) // 8`. Verify that bits `end-start....` and higher, if present (ie. `end-start` is not a multiple of 8), are all zero
* Take all indices `0 <= i < end-start` where the ith bit of `notary_bitfield` equals 1, take `start+i` as the indices of those validators, extract their pubkeys, and add them all together to generate the group pubkey.
* Verify that `len(attester_bitfield) == ceil_div8(end - start)`, where `ceil_div8 = (x + 7) // 8`. Verify that bits `end-start....` and higher, if present (ie. `end-start` is not a multiple of 8), are all zero
* Take all indices `0 <= i < end-start` where the ith bit of `attester_bitfield` equals 1, take `current_epoch_shuffling[start+i]` as the indices of those validators, extract their pubkeys, and add them all together to generate the group pubkey.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ith

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh, don't really care 😄

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funny

* Verify that the `checkpoint_hash` matches the `current_checkpoint`
* Verify that the `aggregate_sig` verifies using the group pubkey and `hash(height_in_epoch + parent + checkpoint_hash + shard_id + shard_block_hash)` as the message.
* AND all indices taken above into the `attester_bitfield`. Add the `balance` of any newly added validators into the `total_attester_deposits`.

Extend the list of `AggregateVote` objects in the `active_state` , ordering the new additions by `shard_block_hash`.

Verify that the `AggregateVote` objects include the first attester at that height (ie. `height_cutoffs[height_in_epoch]`); this attester will be the proposer of the block.
Verify that one of the `AggregateVote` objects includes the first attester at the current height (ie. `current_epoch_shuffling[height_cutoffs[height_in_epoch]]`); this attester can be considered to be the proposer of the block.

### Epoch transitions

Expand All @@ -307,17 +313,17 @@ When the current block height (ie. the height in the active state) is 0 mod SHAR
* If `total_attester_deposits * 3 >= total_deposits * 2`, set `crystallized_state.justified_epoch` to equal `crystallized_state.current_epoch` (note: this is still the previous epoch at this point in the computation). If this happens, and the justified epoch was previously `crystallized_state.current_epoch - 1`, set the `crystallized_state.finalized_epoch` to equal that value.
* Compute the `online_reward` and `offline_penalty` based on the Casper FFG incentive and quadratic leak rules (not yet fully specified)
* Add the `online_reward` to every validator who participated in the last epoch, and subtract the `offline_penalty` from everyone who did not
* Set `attester_bitfield` to be all zeroes, with length `ceil_div8(len(active_validators))`. Set `total_attester_deposits` to 0

### Calculate rewards for crosslinks

Repeat for every shard S:

* Take the set of `shard_block_hash` values that have been proposed for S (call this ROOTS)
* Take the set of `shard_block_hash` values that have been proposed for S in the attestations (call this set ROOTS)
Copy link
Owner Author

@hwwhww hwwhww Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The writing style of this paragraph is quite different from the others; IMO it's more readable if:

Repeat for every shard s:

  • Take the set of shard_block_hash values that have been proposed for shard s in the attestations; call this set roots

* Take the ROOT in ROOTS such that the total deposit size of the subset of validators that have voted for `shard_block_hash` ROOT and `shard_id` S is maximal; call this BESTROOT
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Take root in roots such that the total deposit size of the subset of validators that have voted for shard_block_hash and shard s is maximal; call this best_root

* For every validator that voted for BESTROOT, increment their balance by `online_crosslink_reward`. For everyone else who was assigned to a shard (ie. not the proposers of the last 8 blocks), decrement their balance by `offline_crosslink_penalty`
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should replace 8 with END_EPOCH_GRACE_PERIOD.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* If the size of the subset that voted * 3 >= `total_deposits * 2`, and `crosslink_records[shard_id].epoch < last_finalized_epoch`, set `crosslink_records[shard_id]` to `{epoch: current_epoch, hash: BESTROOT}`
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BESTROOT -> best_root



### Reshuffling

If `current_epoch - crosslink_seed_last_reset` is an exact power of two, then using `temp_seed = blake(crosslink_seed + bytes([log2(current_epoch - crosslink_seed_last_reset)]))`, set `current_shuffling = get_shuffling(temp_seed, len(new_active_validators))`. Note that all of the temp committees are predictable from the `crosslink_seed`, but their positioning stretches out exponentially (eg. 10001 to 10002, 10002 to 10004, 10004 to 10008, 10008 to 10016...).
Expand All @@ -326,18 +332,22 @@ The exponential backoff ensures that, if there has not been a crosslink for N ep

### Dynasty transition

If the last two epochs were both justified, then:
If:

1. The last two epochs were both justified
2. `crosslink_records[shard_id].epoch >= last_finalized_epoch` for every `shard_id` where `(shard_id - next_shard) % SHARD_COUNT < len(shard_cutoffs)`(ie. every crosslink that was supposed to be updated actually was updated)

Then:

* Set `crystallized_state.dynasty += 1`
* Set `crosslink_seed = blake(crosslink_seed)` # Pending a real RNG
* Set `crystallized_state.current_dynasty += 1`
* Set `crosslink_seed = blake(crosslink_seed)` **# Pending a real RNG**
* Go through all `queued_validators`, in order from first to last. Any validators whose `switch_dynasty` is equal to or earlier than the new dynasty are immediately added to the end of `active_validators` (setting `switch_dynasty` to the highest possible integer), up to a maximum of `(len(crystallized_state.active_validators) // 30) + 1` (notice that because `queued_validators` is sorted, it suffices to check the queued validators at the beginning until either you've processed that many, or you reach one whose `switch_dynasty` is later than the current dynasty)
* Go through all `active_valdidators`, and move any with either (i) balance equal to <= 50% of their initial balance, or (ii) `switch_dynasty` equal to or less than the new current dynasty, to `exited_validators`, moving up to a maximum of `(len(crystallized_state.active_validators) // 30) + 1` validators

### Miscellaneous

* Increment the current epoch
* Set `current_epoch += 1`
* Set the `current_checkpoint` to the hash of the previous block
* Reset the FFG voter bitfield and AggregateVote list


-------
Expand Down