Added 2/3/4 cycle finalization options
Suppose B1, B2, B3, B4 are consecutive blocks and we are now processing the end of the cycle containing B4. * If B4 is justified using source B3, then B3 is finalized. * If B4 is justified using source B2, and B3 has been justified, then B2 is finalized. * If B3 is justified using source B1, and B1 has been justified, then B1 is finalized.
This commit is contained in:
parent
252a24cff0
commit
403253c879
|
@ -217,8 +217,11 @@ The `BeaconState` has the following fields:
|
||||||
'last_state_recalculation_slot': 'uint64',
|
'last_state_recalculation_slot': 'uint64',
|
||||||
# Last finalized slot
|
# Last finalized slot
|
||||||
'last_finalized_slot': 'uint64',
|
'last_finalized_slot': 'uint64',
|
||||||
# Last justified slot
|
# Justification source
|
||||||
'last_justified_slot': 'uint64',
|
'justification_source': 'uint64',
|
||||||
|
'prev_cycle_justification_source': 'uint64',
|
||||||
|
# Recent justified slot bitmask
|
||||||
|
'justified_slot_bitfield': 'uint64',
|
||||||
# Committee members and their assigned shard, per slot
|
# Committee members and their assigned shard, per slot
|
||||||
'shard_and_committee_for_slots': [[ShardAndCommittee]],
|
'shard_and_committee_for_slots': [[ShardAndCommittee]],
|
||||||
# Persistent shard committees
|
# Persistent shard committees
|
||||||
|
@ -666,7 +669,9 @@ def on_startup(initial_validator_entries: List[Any], genesis_time: uint64, pow_h
|
||||||
crosslinks=crosslinks,
|
crosslinks=crosslinks,
|
||||||
last_state_recalculation_slot=0,
|
last_state_recalculation_slot=0,
|
||||||
last_finalized_slot=0,
|
last_finalized_slot=0,
|
||||||
last_justified_slot=0,
|
justification_source=0,
|
||||||
|
prev_cycle_justification_source=0,
|
||||||
|
justified_slot_bitfield=0,
|
||||||
shard_and_committee_for_slots=x + x,
|
shard_and_committee_for_slots=x + x,
|
||||||
persistent_committees=split(shuffle(validators, bytes([0] * 32)), SHARD_COUNT),
|
persistent_committees=split(shuffle(validators, bytes([0] * 32)), SHARD_COUNT),
|
||||||
persistent_committee_reassignments=[],
|
persistent_committee_reassignments=[],
|
||||||
|
@ -771,59 +776,6 @@ def exit_validator(index, state, block, penalize, current_slot):
|
||||||
add_validator_set_change_record(state, index, validator.pubkey, EXIT)
|
add_validator_set_change_record(state, index, validator.pubkey, EXIT)
|
||||||
```
|
```
|
||||||
|
|
||||||
## On startup
|
|
||||||
|
|
||||||
Run the following code:
|
|
||||||
|
|
||||||
```python
|
|
||||||
def on_startup(initial_validator_entries: List[Any]) -> BeaconState:
|
|
||||||
# Induct validators
|
|
||||||
validators = []
|
|
||||||
for pubkey, proof_of_possession, withdrawal_shard, withdrawal_address, \
|
|
||||||
randao_commitment in initial_validator_entries:
|
|
||||||
add_validator(
|
|
||||||
validators=validators,
|
|
||||||
pubkey=pubkey,
|
|
||||||
proof_of_possession=proof_of_possession,
|
|
||||||
withdrawal_shard=withdrawal_shard,
|
|
||||||
withdrawal_address=withdrawal_address,
|
|
||||||
randao_commitment=randao_commitment,
|
|
||||||
current_slot=0,
|
|
||||||
status=ACTIVE,
|
|
||||||
)
|
|
||||||
# Setup state
|
|
||||||
x = get_new_shuffling(bytes([0] * 32), validators, 0)
|
|
||||||
crosslinks = [
|
|
||||||
CrosslinkRecord(
|
|
||||||
slot=0,
|
|
||||||
hash=bytes([0] * 32)
|
|
||||||
)
|
|
||||||
for i in range(SHARD_COUNT)
|
|
||||||
]
|
|
||||||
state = BeaconState(
|
|
||||||
validator_set_change_slot=0,
|
|
||||||
validators=validators,
|
|
||||||
crosslinks=crosslinks,
|
|
||||||
last_state_recalculation_slot=0,
|
|
||||||
last_finalized_slot=0,
|
|
||||||
last_justified_slot=0,
|
|
||||||
shard_and_committee_for_slots=x + x,
|
|
||||||
persistent_committees=split(shuffle(validators, bytes([0] * 32)), SHARD_COUNT),
|
|
||||||
persistent_committee_reassignments=[],
|
|
||||||
deposits_penalized_in_period=[],
|
|
||||||
next_shuffling_seed=b'\x00'*32,
|
|
||||||
validator_set_delta_hash_chain=bytes([0] * 32), # stub
|
|
||||||
pre_fork_version=INITIAL_FORK_VERSION,
|
|
||||||
post_fork_version=INITIAL_FORK_VERSION,
|
|
||||||
fork_slot_number=0,
|
|
||||||
pending_attestations=[],
|
|
||||||
recent_block_hashes=[bytes([0] * 32) for _ in range(CYCLE_LENGTH * 2)],
|
|
||||||
randao_mix=bytes([0] * 32) # stub
|
|
||||||
)
|
|
||||||
|
|
||||||
return state
|
|
||||||
```
|
|
||||||
|
|
||||||
## Per-block processing
|
## Per-block processing
|
||||||
|
|
||||||
This procedure should be carried out every beacon block.
|
This procedure should be carried out every beacon block.
|
||||||
|
@ -860,7 +812,7 @@ def update_ancestor_hashes(parent_ancestor_hashes: List[Hash32],
|
||||||
For each `AttestationRecord` object `obj`:
|
For each `AttestationRecord` object `obj`:
|
||||||
|
|
||||||
* Verify that `slot <= block.slot - MIN_ATTESTATION_INCLUSION_DELAY` and `slot >= max(parent.slot - CYCLE_LENGTH + 1, 0)`.
|
* Verify that `slot <= block.slot - MIN_ATTESTATION_INCLUSION_DELAY` and `slot >= max(parent.slot - CYCLE_LENGTH + 1, 0)`.
|
||||||
* Verify that `justified_slot` is equal to or earlier than `last_justified_slot`.
|
* Verify that `justified_slot` is equal to `justification_source if slot >= block.slot - (block.slot % CYCLE_LENGTH) else prev_cycle_justification_source`
|
||||||
* Verify that `justified_block_hash` is the hash of the block in the current chain at the slot -- `justified_slot`.
|
* Verify that `justified_block_hash` is the hash of the block in the current chain at the slot -- `justified_slot`.
|
||||||
* Verify that either `last_crosslink_hash` or `shard_block_hash` equals `state.crosslinks[shard].shard_block_hash`.
|
* Verify that either `last_crosslink_hash` or `shard_block_hash` equals `state.crosslinks[shard].shard_block_hash`.
|
||||||
* Compute `full_parent_hashes` = `[get_block_hash(state, block, slot - CYCLE_LENGTH + i) for i in range(1, CYCLE_LENGTH - len(parent_hashes) + 1)] + parent_hashes` (eg, if `CYCLE_LENGTH = 4`, `slot = 5`, the actual block hashes starting from slot 0 are `Z A B C D E F G H I J`, and `parent_hashes = [D', E']` then `parent_hashes = [B, C, D' E']`). Note that when *creating* an attestation for a block, the hash of that block itself won't yet be in the `state`, so you would need to add it explicitly.
|
* Compute `full_parent_hashes` = `[get_block_hash(state, block, slot - CYCLE_LENGTH + i) for i in range(1, CYCLE_LENGTH - len(parent_hashes) + 1)] + parent_hashes` (eg, if `CYCLE_LENGTH = 4`, `slot = 5`, the actual block hashes starting from slot 0 are `Z A B C D E F G H I J`, and `parent_hashes = [D', E']` then `parent_hashes = [B, C, D' E']`). Note that when *creating* an attestation for a block, the hash of that block itself won't yet be in the `state`, so you would need to add it explicitly.
|
||||||
|
@ -987,13 +939,22 @@ _Note: `last_state_recalculation_slot` will always be a multiple of `CYCLE_LENGT
|
||||||
* Let `total_balance = sum([v.balance for v in active_validators])`
|
* Let `total_balance = sum([v.balance for v in active_validators])`
|
||||||
* Let `this_cycle_attestations = [a for a in state.pending_attestations if s <= a.slot < s + CYCLE_LENGTH]` (note: this is the set of attestations _of slots in the cycle `s...s+CYCLE_LENGTH-1`_, not attestations _that got included in the chain during the cycle `s...s+CYCLE_LENGTH-1`_)
|
* Let `this_cycle_attestations = [a for a in state.pending_attestations if s <= a.slot < s + CYCLE_LENGTH]` (note: this is the set of attestations _of slots in the cycle `s...s+CYCLE_LENGTH-1`_, not attestations _that got included in the chain during the cycle `s...s+CYCLE_LENGTH-1`_)
|
||||||
* Let `prev_cycle_attestations = [a for a in state.pending_attestations if s - CYCLE_LENGTH <= a.slot < s]
|
* Let `prev_cycle_attestations = [a for a in state.pending_attestations if s - CYCLE_LENGTH <= a.slot < s]
|
||||||
* Let `this_cycle_s_attestations = [a for a in this_cycle_attestations if get_block_hash(state, block, s) in a.parent_hashes]
|
* Let `this_cycle_s_attestations = [a for a in this_cycle_attestations if get_block_hash(state, block, s) in a.parent_hashes and a.justified_slot == state.justification_source]
|
||||||
|
* Let `prev_s_attestations = [a for a in this_cycle_attestations + prev_cycle_attestations if get_block_hash(state, block, s - CYCLE_LENGTH) in a.parent_hashes and a.justified_slot == state.prev_cycle_justification_source]
|
||||||
* Let `s_attesters` be the union of the validator index sets given by `[get_attestation_participants(state, a) for a in this_cycle_s_attestations]`
|
* Let `s_attesters` be the union of the validator index sets given by `[get_attestation_participants(state, a) for a in this_cycle_s_attestations]`
|
||||||
|
* Let `prev_s_attesters` be the union of the validator index sets given by `[get_attestation_participants(state, a) for a in this_cycle_s_attestations]`
|
||||||
* Let `total_balance_attesting_at_s = sum([v.balance for v in s_attesters])`
|
* Let `total_balance_attesting_at_s = sum([v.balance for v in s_attesters])`
|
||||||
|
* Let `total_balance_attesting_at_prev_s = sum([v.balance for v in prev_s_attesters])`
|
||||||
|
|
||||||
#### Adjust justified slots and crosslink status
|
#### Adjust justified slots and crosslink status
|
||||||
|
|
||||||
* If `3 * total_balance_attesting_at_s >= 2 * total_balance` then first (i) if `last_justified_slot == s - CYCLE_LENGTH`, set `last_finalized_slot = last_justified_slot`, then (ii) set `last_justified_slot = s`.
|
* Set `state.justified_slot_bitfield = (state.justified_slot_bitfield * 2) % 2**64`.
|
||||||
|
* If `3 * total_balance_attesting_at_prev_s >= 2 * total_balance` then set `state.justified_slot_bitfield &= 2` (ie. flip the second lowest bit to 1) and `new_justification_source = prev_s`.
|
||||||
|
* If `3 * total_balance_attesting_at_s >= 2 * total_balance` then set `state.justified_slot_bitfield &= 1` (ie. flip the lowest bit to 1) and `new_justification_source = s`.
|
||||||
|
* If `justification_source == prev_s and state.justified_slot_bitfield % 4 == 3`, set `last_finalized_slot = justification_source`.
|
||||||
|
* If `justification_source == prev_s - 2 * CYCLE_LENGTH and state.justified_slot_bitfield % 16 in (15, 14)`, set `last_finalized_slot = justification_source`.
|
||||||
|
* If `justification_source == prev_s - CYCLE_LENGTH and state.justified_slot_bitfield % 8 == 7`, set `last_finalized_slot = justification_source`.
|
||||||
|
* Set `prev_cycle_justification_source = justification_source` and `justification_source = new_justification_source`.
|
||||||
|
|
||||||
For every `(shard, shard_block_hash)` tuple:
|
For every `(shard, shard_block_hash)` tuple:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue