All tests passed

This commit is contained in:
Dankrad Feist 2020-04-28 01:09:20 +01:00
parent 2449db1bb6
commit 0e2931b9b3
No known key found for this signature in database
GPG Key ID: 6815E6A20BEBBABA
6 changed files with 121 additions and 184 deletions

View File

@ -208,8 +208,6 @@ EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 4096
EPOCHS_PER_CUSTODY_PERIOD: 8
# 2**11 (= 2,048) epochs
CUSTODY_PERIOD_TO_RANDAO_PADDING: 8
# 2**7 (= 128) epochs
MAX_REVEAL_LATENESS_DECREMENT: 128
# Max operations
# 2**8 (= 256)

View File

@ -282,6 +282,7 @@ class Validator(Container):
next_custody_secret_to_reveal: uint64
# TODO: The max_reveal_lateness doesn't really make sense anymore.
# So how do we incentivise early custody key reveals now?
all_custody_secrets_revealed_epoch: Epoch # to be initialized to FAR_FUTURE_EPOCH
```
### Extended `BeaconBlockBody`
@ -925,6 +926,59 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
state.previous_epoch_attestations.append(pending_attestation)
```
##### New deposits
```python
def process_deposit(state: BeaconState, deposit: Deposit) -> None:
# Verify the Merkle branch
assert is_valid_merkle_branch(
leaf=hash_tree_root(deposit.data),
branch=deposit.proof,
depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the List length mix-in
index=state.eth1_deposit_index,
root=state.eth1_data.deposit_root,
)
# Deposits must be processed in order
state.eth1_deposit_index += 1
pubkey = deposit.data.pubkey
amount = deposit.data.amount
validator_pubkeys = [v.pubkey for v in state.validators]
if pubkey not in validator_pubkeys:
# Verify the deposit signature (proof of possession) which is not checked by the deposit contract
deposit_message = DepositMessage(
pubkey=deposit.data.pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials,
amount=deposit.data.amount,
)
domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
signing_root = compute_signing_root(deposit_message, domain)
if not bls.Verify(pubkey, signing_root, deposit.data.signature):
return
# Add validator and balance entries
# TODO: This function is duplicated from phase 1 just because the validator definition
# has changed and we need to initialize it properly. Is there a better solution for
# this?
state.validators.append(Validator(
pubkey=pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials,
activation_eligibility_epoch=FAR_FUTURE_EPOCH,
activation_epoch=FAR_FUTURE_EPOCH,
exit_epoch=FAR_FUTURE_EPOCH,
withdrawable_epoch=FAR_FUTURE_EPOCH,
effective_balance=min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE),
next_custody_secret_to_reveal=get_custody_period_for_validator(ValidatorIndex(len(state.validators)), get_current_epoch(state)),
all_custody_secrets_revealed_epoch=FAR_FUTURE_EPOCH,
))
state.balances.append(amount)
else:
# Increase balance by deposit amount
index = ValidatorIndex(validator_pubkeys.index(pubkey))
increase_balance(state, index, amount)
```
##### New Attester slashing processing
```python

View File

@ -293,7 +293,12 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) ->
epoch_to_sign = get_randao_epoch_for_custody_period(revealer.next_custody_secret_to_reveal, reveal.revealer_index)
custody_reveal_period = get_custody_period_for_validator(reveal.revealer_index, get_current_epoch(state))
assert revealer.next_custody_secret_to_reveal < custody_reveal_period
# Only past custody periods can be revealed, except after exiting the exit
# period can be revealed
assert (revealer.next_custody_secret_to_reveal < custody_reveal_period
or (revealer.exit_epoch <= get_current_epoch(state) and
revealer.next_custody_secret_to_reveal
<= get_custody_period_for_validator(reveal.revealer_index, revealer.exit_epoch - 1)))
# Revealed validator is active or exited, but not withdrawn
assert is_slashable_validator(revealer, get_current_epoch(state))
@ -304,6 +309,10 @@ def process_custody_key_reveal(state: BeaconState, reveal: CustodyKeyReveal) ->
assert bls.Verify(revealer.pubkey, signing_root, reveal.reveal)
# Process reveal
if (revealer.exit_epoch <= get_current_epoch(state) and
revealer.next_custody_secret_to_reveal
== get_custody_period_for_validator(reveal.revealer_index, revealer.exit_epoch - 1)):
revealer.all_custody_secrets_revealed_epoch = get_current_epoch(state)
revealer.next_custody_secret_to_reveal += 1
# Reward Block Proposer
@ -480,4 +489,22 @@ After `process_final_updates(state)`, additional updates are made for the custod
def process_custody_final_updates(state: BeaconState) -> None:
# Clean up exposed RANDAO key reveals
state.exposed_derived_secrets[get_current_epoch(state) % EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS] = []
# Reset withdrawable epochs if challenge records are empty
records = state.custody_chunk_challenge_records
validator_indices_in_records = set(
[record.responder_index for record in records]
)
for index, validator in enumerate(state.validators):
if validator.exit_epoch != FAR_FUTURE_EPOCH:
if (index in validator_indices_in_records
or validator.all_custody_secrets_revealed_epoch == FAR_FUTURE_EPOCH):
# Delay withdrawable epochs if challenge records are not empty or not all
# custody secrets revealed
validator.withdrawable_epoch = FAR_FUTURE_EPOCH
else:
# Reset withdrawable epochs if challenge records are empty
if validator.withdrawable_epoch == FAR_FUTURE_EPOCH:
validator.withdrawable_epoch = Epoch(validator.all_custody_secrets_revealed_epoch
+ MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
```

View File

@ -79,7 +79,7 @@ def upgrade_to_phase1(pre: phase0.BeaconState) -> BeaconState:
exit_epoch=phase0_validator.exit_epoch,
withdrawable_epoch=phase0_validator.withdrawable_epoch,
next_custody_secret_to_reveal=get_custody_period_for_validator(ValidatorIndex(i), epoch),
max_reveal_lateness=0, # TODO custody refactor. Outdated?
all_custody_secrets_revealed_epoch=FAR_FUTURE_EPOCH,
) for i, phase0_validator in enumerate(pre.validators)
),
balances=pre.balances,

View File

@ -37,9 +37,10 @@ def get_valid_early_derived_secret_reveal(spec, state, epoch=None):
)
def get_valid_custody_key_reveal(spec, state, period=None):
def get_valid_custody_key_reveal(spec, state, period=None, validator_index=None):
current_epoch = spec.get_current_epoch(state)
revealer_index = spec.get_active_validator_indices(state, current_epoch)[0]
revealer_index = (spec.get_active_validator_indices(state, current_epoch)[0]
if validator_index is None else validator_index)
revealer = state.validators[revealer_index]
if period is None:

View File

@ -1,16 +1,15 @@
from eth2spec.test.helpers.custody import (
get_valid_bit_challenge,
get_valid_chunk_challenge,
get_valid_custody_bit_response,
get_valid_custody_chunk_response,
get_valid_custody_key_reveal,
get_custody_test_vector,
get_custody_merkle_root,
get_shard_transition
)
from eth2spec.test.helpers.attestations import (
get_valid_attestation,
get_valid_on_time_attestation,
)
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.helpers.state import next_epoch, transition_to
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.context import (
with_all_phases_except,
@ -19,10 +18,6 @@ from eth2spec.test.context import (
from eth2spec.test.phase_0.block_processing.test_process_attestation import run_attestation_processing
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with
from eth2spec.test.phase_1.block_processing.test_process_bit_challenge import (
run_bit_challenge_processing,
run_custody_bit_response_processing,
)
from eth2spec.test.phase_1.block_processing.test_process_chunk_challenge import (
run_chunk_challenge_processing,
run_custody_chunk_response_processing,
@ -30,8 +25,8 @@ from eth2spec.test.phase_1.block_processing.test_process_chunk_challenge import
from eth2spec.test.phase_1.block_processing.test_process_custody_key_reveal import run_custody_key_reveal_processing
def run_process_final_custody_updates(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_final_custody_updates')
def run_process_custody_final_updates(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_custody_final_updates')
@with_all_phases_except(['phase0'])
@ -40,7 +35,7 @@ def test_validator_withdrawal_delay(spec, state):
spec.initiate_validator_exit(state, 0)
assert state.validators[0].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
yield from run_process_final_custody_updates(spec, state)
yield from run_process_custody_final_updates(spec, state)
assert state.validators[0].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
@ -61,100 +56,39 @@ def test_validator_withdrawal_reenable_after_custody_reveal(spec, state):
apply_empty_block(spec, state)
while (state.validators[0].next_custody_secret_to_reveal
<= spec.get_custody_period_for_validator(state, 0, state.validators[0].exit_epoch - 1)):
<= spec.get_custody_period_for_validator(0, state.validators[0].exit_epoch - 1)):
custody_key_reveal = get_valid_custody_key_reveal(spec, state, validator_index=0)
_, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal)
yield from run_process_final_custody_updates(spec, state)
yield from run_process_custody_final_updates(spec, state)
assert state.validators[0].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
@with_all_phases_except(['phase0'])
@spec_state_test
def test_validator_withdrawal_suspend_after_bit_challenge(spec, state):
state.slot = spec.SLOTS_PER_EPOCH
attestation = get_valid_attestation(spec, state, signed=True)
test_vector = get_custody_test_vector(
spec.get_custody_chunk_count(attestation.data.crosslink) * spec.BYTES_PER_CUSTODY_CHUNK)
shard_root = get_custody_merkle_root(test_vector)
attestation.data.crosslink.data_root = shard_root
attestation.custody_bits[0] = 0
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_epoch(spec, state)
apply_empty_block(spec, state)
_, _, _ = run_attestation_processing(spec, state, attestation)
validator_index = spec.get_crosslink_committee(
state,
attestation.data.target.epoch,
attestation.data.crosslink.shard
)[0]
spec.initiate_validator_exit(state, validator_index)
assert state.validators[validator_index].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
next_epoch(spec, state)
apply_empty_block(spec, state)
assert state.validators[validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
while spec.get_current_epoch(state) < state.validators[validator_index].exit_epoch:
next_epoch(spec, state)
apply_empty_block(spec, state)
while (state.validators[validator_index].next_custody_secret_to_reveal
<= spec.get_custody_period_for_validator(
state,
validator_index,
state.validators[validator_index].exit_epoch - 1)):
custody_key_reveal = get_valid_custody_key_reveal(spec, state, validator_index=validator_index)
_, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal)
next_epoch(spec, state)
apply_empty_block(spec, state)
challenge = get_valid_bit_challenge(spec, state, attestation)
_, _, _ = run_bit_challenge_processing(spec, state, challenge)
yield from run_process_final_custody_updates(spec, state)
assert state.validators[validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
@with_all_phases_except(['phase0'])
@spec_state_test
def test_validator_withdrawal_suspend_after_chunk_challenge(spec, state):
state.slot = spec.SLOTS_PER_EPOCH
transition_to(spec, state, state.slot + 1)
shard = 0
offset_slots = spec.get_offset_slots(state, shard)
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots))
data_index = 0
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True, shard_transition=shard_transition)
attestation = get_valid_attestation(spec, state, signed=True)
test_vector = get_custody_test_vector(
spec.get_custody_chunk_count(attestation.data.crosslink) * spec.BYTES_PER_CUSTODY_CHUNK)
shard_root = get_custody_merkle_root(test_vector)
attestation.data.crosslink.data_root = shard_root
attestation.custody_bits[0] = 0
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_epoch(spec, state)
apply_empty_block(spec, state)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
_, _, _ = run_attestation_processing(spec, state, attestation)
validator_index = spec.get_crosslink_committee(
validator_index = spec.get_beacon_committee(
state,
attestation.data.target.epoch,
attestation.data.crosslink.shard
attestation.data.slot,
attestation.data.index
)[0]
spec.initiate_validator_exit(state, validator_index)
assert state.validators[validator_index].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
next_epoch(spec, state)
apply_empty_block(spec, state)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH)
assert state.validators[validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
@ -164,7 +98,6 @@ def test_validator_withdrawal_suspend_after_chunk_challenge(spec, state):
while (state.validators[validator_index].next_custody_secret_to_reveal
<= spec.get_custody_period_for_validator(
state,
validator_index,
state.validators[validator_index].exit_epoch - 1)):
custody_key_reveal = get_valid_custody_key_reveal(spec, state, validator_index=validator_index)
@ -173,108 +106,33 @@ def test_validator_withdrawal_suspend_after_chunk_challenge(spec, state):
next_epoch(spec, state)
apply_empty_block(spec, state)
challenge = get_valid_chunk_challenge(spec, state, attestation)
challenge = get_valid_chunk_challenge(spec, state, attestation, shard_transition)
_, _, _ = run_chunk_challenge_processing(spec, state, challenge)
yield from run_process_final_custody_updates(spec, state)
yield from run_process_custody_final_updates(spec, state)
assert state.validators[validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
@with_all_phases_except(['phase0'])
@spec_state_test
def test_validator_withdrawal_resume_after_bit_challenge_response(spec, state):
state.slot = spec.SLOTS_PER_EPOCH
attestation = get_valid_attestation(spec, state, signed=True)
test_vector = get_custody_test_vector(
spec.get_custody_chunk_count(attestation.data.crosslink) * spec.BYTES_PER_CUSTODY_CHUNK)
shard_root = get_custody_merkle_root(test_vector)
attestation.data.crosslink.data_root = shard_root
attestation.custody_bits[0] = 0
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_epoch(spec, state)
apply_empty_block(spec, state)
_, _, _ = run_attestation_processing(spec, state, attestation)
validator_index = spec.get_crosslink_committee(
state,
attestation.data.target.epoch,
attestation.data.crosslink.shard
)[0]
spec.initiate_validator_exit(state, validator_index)
assert state.validators[validator_index].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
next_epoch(spec, state)
apply_empty_block(spec, state)
assert state.validators[validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
while spec.get_current_epoch(state) < state.validators[validator_index].exit_epoch:
next_epoch(spec, state)
apply_empty_block(spec, state)
while (state.validators[validator_index].next_custody_secret_to_reveal
<= spec.get_custody_period_for_validator(
state,
validator_index,
state.validators[validator_index].exit_epoch - 1)):
custody_key_reveal = get_valid_custody_key_reveal(spec, state, validator_index=validator_index)
_, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal)
next_epoch(spec, state)
apply_empty_block(spec, state)
challenge = get_valid_bit_challenge(spec, state, attestation)
_, _, _ = run_bit_challenge_processing(spec, state, challenge)
next_epoch(spec, state)
apply_empty_block(spec, state)
assert state.validators[validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
bit_challenge_index = state.custody_bit_challenge_index - 1
response = get_valid_custody_bit_response(
spec,
state,
challenge,
test_vector,
bit_challenge_index,
invalid_chunk_bit=False)
_, _, _ = run_custody_bit_response_processing(spec, state, response)
yield from run_process_final_custody_updates(spec, state)
assert state.validators[validator_index].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
@with_all_phases_except(['phase0'])
@spec_state_test
def test_validator_withdrawal_resume_after_chunk_challenge_response(spec, state):
state.slot = spec.SLOTS_PER_EPOCH
transition_to(spec, state, state.slot + 1)
shard = 0
offset_slots = spec.get_offset_slots(state, shard)
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots))
data_index = 0
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True, shard_transition=shard_transition)
attestation = get_valid_attestation(spec, state, signed=True)
test_vector = get_custody_test_vector(
spec.get_custody_chunk_count(attestation.data.crosslink) * spec.BYTES_PER_CUSTODY_CHUNK)
shard_root = get_custody_merkle_root(test_vector)
attestation.data.crosslink.data_root = shard_root
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
next_epoch(spec, state)
apply_empty_block(spec, state)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
_, _, _ = run_attestation_processing(spec, state, attestation)
validator_index = spec.get_crosslink_committee(
validator_index = spec.get_beacon_committee(
state,
attestation.data.target.epoch,
attestation.data.crosslink.shard
attestation.data.slot,
attestation.data.index
)[0]
spec.initiate_validator_exit(state, validator_index)
@ -291,7 +149,6 @@ def test_validator_withdrawal_resume_after_chunk_challenge_response(spec, state)
while (state.validators[validator_index].next_custody_secret_to_reveal
<= spec.get_custody_period_for_validator(
state,
validator_index,
state.validators[validator_index].exit_epoch - 1)):
custody_key_reveal = get_valid_custody_key_reveal(spec, state, validator_index=validator_index)
@ -300,7 +157,7 @@ def test_validator_withdrawal_resume_after_chunk_challenge_response(spec, state)
next_epoch(spec, state)
apply_empty_block(spec, state)
challenge = get_valid_chunk_challenge(spec, state, attestation)
challenge = get_valid_chunk_challenge(spec, state, attestation, shard_transition)
_, _, _ = run_chunk_challenge_processing(spec, state, challenge)
@ -310,10 +167,10 @@ def test_validator_withdrawal_resume_after_chunk_challenge_response(spec, state)
assert state.validators[validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
chunk_challenge_index = state.custody_chunk_challenge_index - 1
response = get_valid_custody_chunk_response(spec, state, challenge, test_vector, chunk_challenge_index)
custody_response = get_valid_custody_chunk_response(spec, state, challenge, 2**15 // 3, chunk_challenge_index)
_, _, _ = run_custody_chunk_response_processing(spec, state, response)
_, _, _ = run_custody_chunk_response_processing(spec, state, custody_response)
yield from run_process_final_custody_updates(spec, state)
yield from run_process_custody_final_updates(spec, state)
assert state.validators[validator_index].withdrawable_epoch < spec.FAR_FUTURE_EPOCH