Allow multiple bit challenges, and recover withdrawability
Resolves #864 items 4, 7, 14
This commit is contained in:
parent
c0f3453093
commit
66b152f79e
|
@ -146,7 +146,7 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
|
|||
'challenge_index': 'uint64',
|
||||
'challenger_index': ValidatorIndex,
|
||||
'responder_index': ValidatorIndex,
|
||||
'deadline': Epoch,
|
||||
'inclusion_epoch': Epoch,
|
||||
'crosslink_data_root': Hash,
|
||||
'depth': 'uint64',
|
||||
'chunk_index': 'uint64',
|
||||
|
@ -160,7 +160,7 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
|
|||
'challenge_index': 'uint64',
|
||||
'challenger_index': ValidatorIndex,
|
||||
'responder_index': ValidatorIndex,
|
||||
'deadline': Epoch,
|
||||
'inclusion_epoch': Epoch,
|
||||
'crosslink_data_root': Hash,
|
||||
'chunk_count': 'uint64',
|
||||
'chunk_bits_merkle_root': Hash,
|
||||
|
@ -485,7 +485,7 @@ def process_chunk_challenge(state: BeaconState,
|
|||
challenge_index=state.custody_challenge_index,
|
||||
challenger_index=get_beacon_proposer_index(state),
|
||||
responder_index=challenge.responder_index
|
||||
deadline=get_current_epoch(state) + CUSTODY_RESPONSE_DEADLINE,
|
||||
inclusion_epoch=get_current_epoch(state),
|
||||
crosslink_data_root=challenge.attestation.data.crosslink_data_root,
|
||||
depth=depth,
|
||||
chunk_index=challenge.chunk_index,
|
||||
|
@ -528,10 +528,9 @@ def process_bit_challenge(state: BeaconState,
|
|||
attesters = get_attesting_indices(state, attestation.data, attestation.aggregation_bitfield)
|
||||
assert challenge.responder_index in attesters
|
||||
|
||||
# A validator can be the challenger or responder for at most one challenge at a time
|
||||
# A validator can be the challenger for at most one challenge at a time
|
||||
for record in state.custody_bit_challenge_records:
|
||||
assert record.challenger_index != challenge.challenger_index
|
||||
assert record.responder_index != challenge.responder_index
|
||||
|
||||
# Verify the responder is a valid custody key
|
||||
epoch_to_sign = get_randao_epoch_for_custody_period(
|
||||
|
@ -563,7 +562,7 @@ def process_bit_challenge(state: BeaconState,
|
|||
challenge_index=state.custody_challenge_index,
|
||||
challenger_index=challenge.challenger_index,
|
||||
responder_index=challenge.responder_index,
|
||||
deadline=get_current_epoch(state) + CUSTODY_RESPONSE_DEADLINE,
|
||||
inclusion_epoch=get_current_epoch(state),
|
||||
crosslink_data_root=challenge.attestation.data.crosslink_data_root,
|
||||
chunk_count=chunk_count,
|
||||
chunk_bits_merkle_root=merkle_root(pad_to_power_of_2((challenge.chunk_bits))),
|
||||
|
@ -604,6 +603,8 @@ def process_chunk_challenge_response(state: BeaconState,
|
|||
assert response.chunk_index == challenge.chunk_index
|
||||
# Verify bit challenge data is null
|
||||
assert response.chunk_bits_branch == [] and response.chunk_bits_leaf == ZERO_HASH
|
||||
# Verify minimum delay
|
||||
assert get_current_epoch(state) >= challenge.inclusion_epoch + ACTIVATION_EXIT_DELAY
|
||||
# Verify the chunk matches the crosslink data root
|
||||
assert verify_merkle_branch(
|
||||
leaf=hash_tree_root(response.chunk),
|
||||
|
@ -626,6 +627,9 @@ def process_bit_challenge_response(state: BeaconState,
|
|||
challenge: CustodyBitChallengeRecord) -> None:
|
||||
# Verify chunk index
|
||||
assert response.chunk_index < challenge.chunk_count
|
||||
# Verify responder has not been slashed
|
||||
responder = state.validator_registry[record.responder_index]
|
||||
assert not responder.slashed
|
||||
# Verify the chunk matches the crosslink data root
|
||||
assert verify_merkle_branch(
|
||||
leaf=hash_tree_root(response.chunk),
|
||||
|
@ -671,13 +675,13 @@ Run `process_challenge_deadlines(state)` immediately after `process_reveal_deadl
|
|||
```python
|
||||
def process_challenge_deadlines(state: BeaconState) -> None:
|
||||
for challenge in state.custody_chunk_challenge_records:
|
||||
if get_current_epoch(state) > challenge.deadline:
|
||||
if get_current_epoch(state) > challenge.inclusion_epoch + CUSTODY_RESPONSE_DEADLINE:
|
||||
slash_validator(state, challenge.responder_index, challenge.challenger_index)
|
||||
records = state.custody_chunk_challenge_records
|
||||
records[records.index(challenge)] = CustodyChunkChallengeRecord()
|
||||
|
||||
for challenge in state.custody_bit_challenge_records:
|
||||
if get_current_epoch(state) > challenge.deadline:
|
||||
if get_current_epoch(state) > challenge.inclusion_epoch + CUSTODY_RESPONSE_DEADLINE:
|
||||
slash_validator(state, challenge.responder_index, challenge.challenger_index)
|
||||
records = state.custody_bit_challenge_records
|
||||
records[records.index(challenge)] = CustodyBitChallengeRecord()
|
||||
|
@ -688,6 +692,18 @@ Append this to `process_final_updates(state)`:
|
|||
```python
|
||||
# Clean up exposed RANDAO key reveals
|
||||
state.exposed_derived_secrets[current_epoch % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS] = []
|
||||
# Reset withdrawable epochs if challenge records are empty
|
||||
for index, validator in enumerate(state.validator_registry):
|
||||
eligible = True
|
||||
for records in (state.custody_chunk_challenge_records, state.bit_challenge_records):
|
||||
for filter_func in (lambda rec: rec.challenger_index == index, lambda rec: rec.responder_index == index):
|
||||
if len(list(filter(filter_func, records))) > 0:
|
||||
eligible = False
|
||||
if eligible:
|
||||
if validator.exit_epoch == FAR_FUTURE_EPOCH:
|
||||
validator.withdrawable_epoch = FAR_FUTURE_EPOCH
|
||||
else:
|
||||
validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
```
|
||||
|
||||
In `process_penalties_and_exits`, change the definition of `eligible` to the following (note that it is not a pure function because `state` is declared in the surrounding scope):
|
||||
|
|
Loading…
Reference in New Issue