Merge pull request #1889 from ethereum/dankrad-custody-0.01bit

0.01 bit proof of custody [depends on 256 bit custody atoms]
This commit is contained in:
Danny Ryan 2020-06-16 07:20:16 -06:00 committed by GitHub
commit eec323c7b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 166 additions and 457 deletions

View File

@ -151,3 +151,9 @@ DOMAIN_DEPOSIT: 0x03000000
DOMAIN_VOLUNTARY_EXIT: 0x04000000 DOMAIN_VOLUNTARY_EXIT: 0x04000000
DOMAIN_SELECTION_PROOF: 0x05000000 DOMAIN_SELECTION_PROOF: 0x05000000
DOMAIN_AGGREGATE_AND_PROOF: 0x06000000 DOMAIN_AGGREGATE_AND_PROOF: 0x06000000
<<<<<<< HEAD:configs/mainnet.yaml
# Phase 1
DOMAIN_SHARD_PROPOSAL: 0x80000000
DOMAIN_SHARD_COMMITTEE: 0x81000000
DOMAIN_LIGHT_CLIENT: 0x82000000
DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000

View File

@ -62,14 +62,26 @@ DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000
# Time parameters # Time parameters
# 2**1 (= 2) epochs, 12.8 minutes # 2**1 (= 2) epochs, 12.8 minutes
RANDAO_PENALTY_EPOCHS: 2 RANDAO_PENALTY_EPOCHS: 2
# 2**15 (= 32,768) epochs, ~146 days
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 32768
# 2**14 (= 16,384) epochs ~73 days # 2**14 (= 16,384) epochs ~73 days
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 16384 EPOCHS_PER_CUSTODY_PERIOD: 16384
# 2**11 (= 2,048) epochs, ~9 days
EPOCHS_PER_CUSTODY_PERIOD: 2048
# 2**11 (= 2,048) epochs, ~9 days # 2**11 (= 2,048) epochs, ~9 days
CUSTODY_PERIOD_TO_RANDAO_PADDING: 2048 CUSTODY_PERIOD_TO_RANDAO_PADDING: 2048
# 2**14 (= 16,384) epochs # 2**14 (= 16,384) epochs
CUSTODY_RESPONSE_DEADLINE: 16384 CUSTODY_RESPONSE_DEADLINE: 16384
# 2**15 (= 32,768) epochs, ~146 days
MAX_CHUNK_CHALLENGE_DELAY: 32768
# Misc parameters
# 2**256 - 189
CUSTODY_PRIME: 115792089237316195423570985008687907853269984665640564039457584007913129639747
# 3
CUSTODY_SECRETS: 3
# 2**5 (= 32) bytes
BYTES_PER_CUSTODY_ATOM: 32
# 1/1024 chance of custody bit 1
CUSTODY_PROBABILITY_EXPONENT: 10
# Max operations # Max operations
# 2**8 (= 256) # 2**8 (= 256)

View File

@ -65,13 +65,27 @@ DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000
# 2**1 (= 2) epochs # 2**1 (= 2) epochs
RANDAO_PENALTY_EPOCHS: 2 RANDAO_PENALTY_EPOCHS: 2
# [customized] quicker for testing # [customized] quicker for testing
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 4096 EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 128
# [customized] quicker for testing # [customized] quicker for testing
EPOCHS_PER_CUSTODY_PERIOD: 8 EPOCHS_PER_CUSTODY_PERIOD: 64
# [customized] quicker for testing # [customized] quicker for testing
CUSTODY_PERIOD_TO_RANDAO_PADDING: 8 CUSTODY_PERIOD_TO_RANDAO_PADDING: 8
# [customized] quicker for testing # [customized] quicker for testing
CUSTODY_RESPONSE_DEADLINE: 32 CUSTODY_RESPONSE_DEADLINE: 128
# [customize for faster testing]
MAX_CHUNK_CHALLENGE_DELAY: 128
# Misc parameters
# 2**256 - 189
CUSTODY_PRIME: 115792089237316195423570985008687907853269984665640564039457584007913129639747
# 3
CUSTODY_SECRETS: 3
# 2**5 (= 32) bytes
BYTES_PER_CUSTODY_ATOM: 32
# 1/4 chance of custody bit 1 [customized for faster testing]
CUSTODY_PROBABILITY_EXPONENT: 2
# Max operations # Max operations
# 2**8 (= 256) # 2**8 (= 256)

View File

@ -53,15 +53,12 @@
- [`get_shard_committee`](#get_shard_committee) - [`get_shard_committee`](#get_shard_committee)
- [`get_light_client_committee`](#get_light_client_committee) - [`get_light_client_committee`](#get_light_client_committee)
- [`get_shard_proposer_index`](#get_shard_proposer_index) - [`get_shard_proposer_index`](#get_shard_proposer_index)
- [`get_indexed_attestation`](#get_indexed_attestation)
- [`get_committee_count_delta`](#get_committee_count_delta) - [`get_committee_count_delta`](#get_committee_count_delta)
- [`get_start_shard`](#get_start_shard) - [`get_start_shard`](#get_start_shard)
- [`get_shard`](#get_shard) - [`get_shard`](#get_shard)
- [`get_latest_slot_for_shard`](#get_latest_slot_for_shard) - [`get_latest_slot_for_shard`](#get_latest_slot_for_shard)
- [`get_offset_slots`](#get_offset_slots) - [`get_offset_slots`](#get_offset_slots)
- [Predicates](#predicates) - [Predicates](#predicates)
- [`verify_attestation_custody`](#verify_attestation_custody)
- [Updated `is_valid_indexed_attestation`](#updated-is_valid_indexed_attestation)
- [`is_on_time_attestation`](#is_on_time_attestation) - [`is_on_time_attestation`](#is_on_time_attestation)
- [`is_winning_attestation`](#is_winning_attestation) - [`is_winning_attestation`](#is_winning_attestation)
- [`optional_aggregate_verify`](#optional_aggregate_verify) - [`optional_aggregate_verify`](#optional_aggregate_verify)
@ -78,7 +75,6 @@
- [`verify_empty_shard_transition`](#verify_empty_shard_transition) - [`verify_empty_shard_transition`](#verify_empty_shard_transition)
- [`process_shard_transitions`](#process_shard_transitions) - [`process_shard_transitions`](#process_shard_transitions)
- [New default validator for deposits](#new-default-validator-for-deposits) - [New default validator for deposits](#new-default-validator-for-deposits)
- [New Attester slashing processing](#new-attester-slashing-processing)
- [Light client processing](#light-client-processing) - [Light client processing](#light-client-processing)
- [Epoch transition](#epoch-transition) - [Epoch transition](#epoch-transition)
- [Phase 1 final updates](#phase-1-final-updates) - [Phase 1 final updates](#phase-1-final-updates)
@ -186,7 +182,6 @@ class AttestationData(Container):
class Attestation(Container): class Attestation(Container):
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE] aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
data: AttestationData data: AttestationData
custody_bits_blocks: List[Bitlist[MAX_VALIDATORS_PER_COMMITTEE], MAX_SHARD_BLOCKS_PER_ATTESTATION]
signature: BLSSignature signature: BLSSignature
``` ```
@ -206,8 +201,9 @@ class PendingAttestation(Container):
```python ```python
class IndexedAttestation(Container): class IndexedAttestation(Container):
committee: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE]
attestation: Attestation data: AttestationData
signature: BLSSignature
``` ```
### Extended `AttesterSlashing` ### Extended `AttesterSlashing`
@ -593,17 +589,6 @@ def get_shard_proposer_index(beacon_state: BeaconState, slot: Slot, shard: Shard
return committee[r % len(committee)] return committee[r % len(committee)]
``` ```
#### `get_indexed_attestation`
```python
def get_indexed_attestation(beacon_state: BeaconState, attestation: Attestation) -> IndexedAttestation:
committee = get_beacon_committee(beacon_state, attestation.data.slot, attestation.data.index)
return IndexedAttestation(
committee=committee,
attestation=attestation,
)
```
#### `get_committee_count_delta` #### `get_committee_count_delta`
```python ```python
@ -673,65 +658,6 @@ def get_offset_slots(state: BeaconState, shard: Shard) -> Sequence[Slot]:
### Predicates ### Predicates
#### `verify_attestation_custody`
```python
def verify_attestation_custody(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
"""
Check if ``indexed_attestation`` has valid signature against non-empty custody bits.
"""
attestation = indexed_attestation.attestation
aggregation_bits = attestation.aggregation_bits
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch)
all_pubkeys = []
all_signing_roots = []
for block_index, custody_bits in enumerate(attestation.custody_bits_blocks):
assert len(custody_bits) == len(indexed_attestation.committee)
for participant, aggregation_bit, custody_bit in zip(
indexed_attestation.committee, aggregation_bits, custody_bits
):
if aggregation_bit:
all_pubkeys.append(state.validators[participant].pubkey)
# Note: only 2N distinct message hashes
attestation_wrapper = AttestationCustodyBitWrapper(
attestation_data_root=hash_tree_root(attestation.data),
block_index=block_index,
bit=custody_bit,
)
all_signing_roots.append(compute_signing_root(attestation_wrapper, domain))
else:
assert not custody_bit
return bls.AggregateVerify(all_pubkeys, all_signing_roots, signature=attestation.signature)
```
#### Updated `is_valid_indexed_attestation`
Note that this replaces the Phase 0 `is_valid_indexed_attestation`.
```python
def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool:
"""
Check if ``indexed_attestation`` has valid indices and signature.
"""
# Verify aggregate signature
attestation = indexed_attestation.attestation
aggregation_bits = attestation.aggregation_bits
if not any(aggregation_bits) or len(aggregation_bits) != len(indexed_attestation.committee):
return False
if len(attestation.custody_bits_blocks) == 0:
# fall back on phase0 behavior if there is no shard data.
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch)
all_pubkeys = []
for participant, aggregation_bit in zip(indexed_attestation.committee, aggregation_bits):
if aggregation_bit:
all_pubkeys.append(state.validators[participant].pubkey)
signing_root = compute_signing_root(indexed_attestation.attestation.data, domain)
return bls.FastAggregateVerify(all_pubkeys, signing_root, signature=attestation.signature)
else:
return verify_attestation_custody(state, indexed_attestation)
```
#### `is_on_time_attestation` #### `is_on_time_attestation`
```python ```python
@ -849,16 +775,11 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
else: else:
assert attestation.data.source == state.previous_justified_checkpoint assert attestation.data.source == state.previous_justified_checkpoint
# Type 1: on-time attestations, the custody bits should be non-empty. # Type 1: on-time attestations
if attestation.custody_bits_blocks != []: if is_on_time_attestation(state, attestation):
# Ensure on-time attestation
assert is_on_time_attestation(state, attestation)
# Correct data root count
shard = get_shard(state, attestation)
assert len(attestation.custody_bits_blocks) == len(get_offset_slots(state, shard))
# Correct parent block root # Correct parent block root
assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot)) assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot))
# Type 2: no shard transition, no custody bits # Type 2: no shard transition
else: else:
# Ensure delayed attestation # Ensure delayed attestation
assert data.slot < compute_previous_slot(state.slot) assert data.slot < compute_previous_slot(state.slot)
@ -1081,46 +1002,6 @@ def get_validator_from_deposit(state: BeaconState, deposit: Deposit) -> Validato
) )
``` ```
##### New Attester slashing processing
```python
def get_indices_from_committee(
committee: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE],
bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]) -> Sequence[ValidatorIndex]:
assert len(bits) == len(committee)
return [validator_index for i, validator_index in enumerate(committee) if bits[i]]
```
```python
def process_attester_slashing(state: BeaconState, attester_slashing: AttesterSlashing) -> None:
indexed_attestation_1 = attester_slashing.attestation_1
indexed_attestation_2 = attester_slashing.attestation_2
assert is_slashable_attestation_data(
indexed_attestation_1.attestation.data,
indexed_attestation_2.attestation.data,
)
assert is_valid_indexed_attestation(state, indexed_attestation_1)
assert is_valid_indexed_attestation(state, indexed_attestation_2)
indices_1 = get_indices_from_committee(
indexed_attestation_1.committee,
indexed_attestation_1.attestation.aggregation_bits,
)
indices_2 = get_indices_from_committee(
indexed_attestation_2.committee,
indexed_attestation_2.attestation.aggregation_bits,
)
slashed_any = False
indices = set(indices_1).intersection(indices_2)
for index in sorted(indices):
if is_slashable_validator(state.validators[index], get_current_epoch(state)):
slash_validator(state, index)
slashed_any = True
assert slashed_any
```
#### Light client processing #### Light client processing
```python ```python

View File

@ -60,6 +60,7 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
| `CUSTODY_PRIME` | `2 ** 256 - 189` | - | | `CUSTODY_PRIME` | `2 ** 256 - 189` | - |
| `CUSTODY_SECRETS` | `3` | - | | `CUSTODY_SECRETS` | `3` | - |
| `BYTES_PER_CUSTODY_ATOM` | `32` | bytes | | `BYTES_PER_CUSTODY_ATOM` | `32` | bytes |
| `CUSTODY_PROBABILITY_EXPONENT` | `10` | - |
## Configuration ## Configuration
@ -68,11 +69,11 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
| Name | Value | Unit | Duration | | Name | Value | Unit | Duration |
| - | - | :-: | :-: | | - | - | :-: | :-: |
| `RANDAO_PENALTY_EPOCHS` | `2**1` (= 2) | epochs | 12.8 minutes | | `RANDAO_PENALTY_EPOCHS` | `2**1` (= 2) | epochs | 12.8 minutes |
| `EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS` | `2**14` (= 16,384) | epochs | ~73 days | | `EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS` | `2**15` (= 32,768) | epochs | ~146 days |
| `EPOCHS_PER_CUSTODY_PERIOD` | `2**11` (= 2,048) | epochs | ~9 days | | `EPOCHS_PER_CUSTODY_PERIOD` | `2**14` (= 16,384) | epochs | ~73 days |
| `CUSTODY_PERIOD_TO_RANDAO_PADDING` | `2**11` (= 2,048) | epochs | ~9 days | | `CUSTODY_PERIOD_TO_RANDAO_PADDING` | `2**11` (= 2,048) | epochs | ~9 days |
| `MAX_CHUNK_CHALLENGE_DELAY` | `2**11` (= 2,048) | epochs | ~9 days | | `MAX_CHUNK_CHALLENGE_DELAY` | `2**15` (= 32,768) | epochs | ~146 days |
| `CUSTODY_RESPONSE_DEADLINE` | `2**14` (= 16,384) | epochs | ~73 days | | `CHUNK_RESPONSE_DEADLINE` | `2**14` (= 16,384) | epochs | ~73 days |
### Max operations per block ### Max operations per block
@ -140,7 +141,6 @@ class CustodyChunkResponse(Container):
```python ```python
class CustodySlashing(Container): class CustodySlashing(Container):
# Attestation.custody_bits_blocks[data_index][committee.index(malefactor_index)] is the target custody bit to check.
# (Attestation.data.shard_transition_root as ShardTransition).shard_data_roots[data_index] is the root of the data. # (Attestation.data.shard_transition_root as ShardTransition).shard_data_roots[data_index] is the root of the data.
data_index: uint64 data_index: uint64
malefactor_index: ValidatorIndex malefactor_index: ValidatorIndex
@ -276,7 +276,8 @@ def compute_custody_bit(key: BLSSignature, data: ByteList[MAX_SHARD_BLOCK_SIZE])
custody_atoms = get_custody_atoms(data) custody_atoms = get_custody_atoms(data)
secrets = get_custody_secrets(key) secrets = get_custody_secrets(key)
uhf = universal_hash_function(custody_atoms, secrets) uhf = universal_hash_function(custody_atoms, secrets)
return legendre_bit(uhf + secrets[0], CUSTODY_PRIME) legendre_bits = [legendre_bit(uhf + secrets[0] + i, CUSTODY_PRIME) for i in range(CUSTODY_PROBABILITY_EXPONENT)]
return all(legendre_bits)
``` ```
### `get_randao_epoch_for_custody_period` ### `get_randao_epoch_for_custody_period`
@ -517,9 +518,6 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed
# Verify the attestation # Verify the attestation
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
# TODO: custody_slashing.data is not chunked like shard blocks yet, result is lots of padding.
# ??? What does this mean?
# TODO: can do a single combined merkle proof of data being attested. # TODO: can do a single combined merkle proof of data being attested.
# Verify the shard transition is indeed attested by the attestation # Verify the shard transition is indeed attested by the attestation
shard_transition = custody_slashing.shard_transition shard_transition = custody_slashing.shard_transition
@ -544,18 +542,14 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed
signing_root = compute_signing_root(epoch_to_sign, domain) signing_root = compute_signing_root(epoch_to_sign, domain)
assert bls.Verify(malefactor.pubkey, signing_root, custody_slashing.malefactor_secret) assert bls.Verify(malefactor.pubkey, signing_root, custody_slashing.malefactor_secret)
# Get the custody bit
custody_bits = attestation.custody_bits_blocks[custody_slashing.data_index]
committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)
claimed_custody_bit = custody_bits[committee.index(custody_slashing.malefactor_index)]
# Compute the custody bit # Compute the custody bit
computed_custody_bit = compute_custody_bit(custody_slashing.malefactor_secret, custody_slashing.data) computed_custody_bit = compute_custody_bit(custody_slashing.malefactor_secret, custody_slashing.data)
# Verify the claim # Verify the claim
if claimed_custody_bit != computed_custody_bit: if computed_custody_bit == 1:
# Slash the malefactor, reward the other committee members # Slash the malefactor, reward the other committee members
slash_validator(state, custody_slashing.malefactor_index) slash_validator(state, custody_slashing.malefactor_index)
committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)
others_count = len(committee) - 1 others_count = len(committee) - 1
whistleblower_reward = Gwei(malefactor.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT // others_count) whistleblower_reward = Gwei(malefactor.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT // others_count)
for attester_index in attesters: for attester_index in attesters:
@ -576,7 +570,7 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed
def process_reveal_deadlines(state: BeaconState) -> None: def process_reveal_deadlines(state: BeaconState) -> None:
epoch = get_current_epoch(state) epoch = get_current_epoch(state)
for index, validator in enumerate(state.validators): for index, validator in enumerate(state.validators):
deadline = validator.next_custody_secret_to_reveal + (CUSTODY_RESPONSE_DEADLINE // EPOCHS_PER_CUSTODY_PERIOD) deadline = validator.next_custody_secret_to_reveal + 1
if get_custody_period_for_validator(ValidatorIndex(index), epoch) > deadline: if get_custody_period_for_validator(ValidatorIndex(index), epoch) > deadline:
slash_validator(state, ValidatorIndex(index)) slash_validator(state, ValidatorIndex(index))
``` ```
@ -584,7 +578,7 @@ def process_reveal_deadlines(state: BeaconState) -> None:
```python ```python
def process_challenge_deadlines(state: BeaconState) -> None: def process_challenge_deadlines(state: BeaconState) -> None:
for custody_chunk_challenge in state.custody_chunk_challenge_records: for custody_chunk_challenge in state.custody_chunk_challenge_records:
if get_current_epoch(state) > custody_chunk_challenge.inclusion_epoch + CUSTODY_RESPONSE_DEADLINE: if get_current_epoch(state) > custody_chunk_challenge.inclusion_epoch + EPOCHS_PER_CUSTODY_PERIOD:
slash_validator(state, custody_chunk_challenge.responder_index, custody_chunk_challenge.challenger_index) slash_validator(state, custody_chunk_challenge.responder_index, custody_chunk_challenge.challenger_index)
index_in_records = state.custody_chunk_challenge_records.index(custody_chunk_challenge) index_in_records = state.custody_chunk_challenge_records.index(custody_chunk_challenge)
state.custody_chunk_challenge_records[index_in_records] = CustodyChunkChallengeRecord() state.custody_chunk_challenge_records[index_in_records] = CustodyChunkChallengeRecord()

View File

@ -9,11 +9,9 @@
- [Introduction](#introduction) - [Introduction](#introduction)
- [Fork choice](#fork-choice)
- [Helpers](#helpers) - [Helpers](#helpers)
- [Extended `LatestMessage`](#extended-latestmessage) - [Extended `LatestMessage`](#extended-latestmessage)
- [Updated `update_latest_messages`](#updated-update_latest_messages) - [Updated `update_latest_messages`](#updated-update_latest_messages)
- [Handlers](#handlers)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC --> <!-- /TOC -->
@ -22,12 +20,6 @@
This document is the beacon chain fork choice spec for part of Ethereum 2.0 Phase 1. This document is the beacon chain fork choice spec for part of Ethereum 2.0 Phase 1.
## Fork choice
Due to the changes in the structure of `IndexedAttestation` in Phase 1, `on_attestation` must be re-specified to handle this. The bulk of `on_attestation` has been moved out into a few helpers to reduce code duplication where possible.
The rest of the fork choice remains stable.
### Helpers ### Helpers
#### Extended `LatestMessage` #### Extended `LatestMessage`
@ -54,29 +46,3 @@ def update_latest_messages(store: Store, attesting_indices: Sequence[ValidatorIn
epoch=target.epoch, root=beacon_block_root, shard=shard, shard_root=attestation.data.shard_head_root epoch=target.epoch, root=beacon_block_root, shard=shard, shard_root=attestation.data.shard_head_root
) )
``` ```
### Handlers
```python
def on_attestation(store: Store, attestation: Attestation) -> None:
"""
Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire.
An ``attestation`` that is asserted as invalid may be valid at a later time,
consider scheduling it for later processing in such case.
"""
validate_on_attestation(store, attestation)
store_target_checkpoint_state(store, attestation.data.target)
# Get state at the `target` to fully validate attestation
target_state = store.checkpoint_states[attestation.data.target]
indexed_attestation = get_indexed_attestation(target_state, attestation)
assert is_valid_indexed_attestation(target_state, indexed_attestation)
# Update latest messages for attesting indices
attesting_indices = [
index for i, index in enumerate(indexed_attestation.committee)
if attestation.aggregation_bits[i]
]
update_latest_messages(store, attesting_indices, attestation)
```

View File

@ -16,18 +16,13 @@ def run_on_attestation(spec, state, store, attestation, valid=True):
indexed_attestation = spec.get_indexed_attestation(state, attestation) indexed_attestation = spec.get_indexed_attestation(state, attestation)
spec.on_attestation(store, attestation) spec.on_attestation(store, attestation)
sample_index = indexed_attestation.attesting_indices[0]
if spec.fork == PHASE0: if spec.fork == PHASE0:
sample_index = indexed_attestation.attesting_indices[0]
latest_message = spec.LatestMessage( latest_message = spec.LatestMessage(
epoch=attestation.data.target.epoch, epoch=attestation.data.target.epoch,
root=attestation.data.beacon_block_root, root=attestation.data.beacon_block_root,
) )
else: else:
attesting_indices = [
index for i, index in enumerate(indexed_attestation.committee)
if attestation.aggregation_bits[i]
]
sample_index = attesting_indices[0]
latest_message = spec.LatestMessage( latest_message = spec.LatestMessage(
epoch=attestation.data.target.epoch, epoch=attestation.data.target.epoch,
root=attestation.data.beacon_block_root, root=attestation.data.beacon_block_root,

View File

@ -2,14 +2,13 @@ from lru import LRU
from typing import List from typing import List
from eth2spec.test.context import expect_assertion_error, PHASE0, PHASE1 from eth2spec.test.context import expect_assertion_error, PHASE1
from eth2spec.test.helpers.state import state_transition_and_sign_block, next_epoch, next_slot from eth2spec.test.helpers.state import state_transition_and_sign_block, next_epoch, next_slot
from eth2spec.test.helpers.block import build_empty_block_for_next_slot from eth2spec.test.helpers.block import build_empty_block_for_next_slot
from eth2spec.test.helpers.shard_transitions import get_shard_transition_of_committee from eth2spec.test.helpers.shard_transitions import get_shard_transition_of_committee
from eth2spec.test.helpers.keys import privkeys from eth2spec.test.helpers.keys import privkeys
from eth2spec.utils import bls from eth2spec.utils import bls
from eth2spec.utils.ssz.ssz_typing import Bitlist from eth2spec.utils.ssz.ssz_typing import Bitlist
from eth2spec.test.helpers.custody import get_custody_test_vector
def run_attestation_processing(spec, state, attestation, valid=True): def run_attestation_processing(spec, state, attestation, valid=True):
@ -97,44 +96,7 @@ def build_attestation_data(spec, state, slot, index, shard_transition=None, on_t
return attestation_data return attestation_data
def convert_to_valid_on_time_attestation(spec, state, attestation, shard_transition, def get_valid_on_time_attestation(spec, state, slot=None, index=None, shard_transition=None, signed=False):
signed=False, valid_custody_bits=None):
shard = spec.get_shard(state, attestation)
offset_slots = spec.compute_offset_slots(spec.get_latest_slot_for_shard(state, shard), state.slot + 1)
if valid_custody_bits is not None:
beacon_committee = spec.get_beacon_committee(
state,
attestation.data.slot,
attestation.data.index,
)
custody_secrets = [None for i in beacon_committee]
for i in range(len(beacon_committee)):
period = spec.get_custody_period_for_validator(beacon_committee[i], attestation.data.target.epoch)
epoch_to_sign = spec.get_randao_epoch_for_custody_period(period, beacon_committee[i])
domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch_to_sign)
signing_root = spec.compute_signing_root(spec.Epoch(epoch_to_sign), domain)
custody_secrets[i] = bls.Sign(privkeys[beacon_committee[i]], signing_root)
for i in range(len(offset_slots)):
attestation.custody_bits_blocks.append(
Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in attestation.aggregation_bits])
)
if valid_custody_bits is not None:
test_vector = get_custody_test_vector(shard_transition.shard_block_lengths[i])
for j in range(len(attestation.custody_bits_blocks[i])):
if attestation.aggregation_bits[j]:
attestation.custody_bits_blocks[i][j] = \
spec.compute_custody_bit(custody_secrets[j], test_vector) ^ (not valid_custody_bits)
if signed:
sign_attestation(spec, state, attestation)
return attestation
def get_valid_on_time_attestation(spec, state, slot=None, index=None,
shard_transition=None, valid_custody_bits=None, signed=False):
''' '''
Construct on-time attestation for next slot Construct on-time attestation for next slot
''' '''
@ -149,7 +111,6 @@ def get_valid_on_time_attestation(spec, state, slot=None, index=None,
slot=slot, slot=slot,
index=index, index=index,
shard_transition=shard_transition, shard_transition=shard_transition,
valid_custody_bits=valid_custody_bits,
signed=signed, signed=signed,
on_time=True, on_time=True,
) )
@ -174,7 +135,6 @@ def get_valid_attestation(spec,
index=None, index=None,
filter_participant_set=None, filter_participant_set=None,
shard_transition=None, shard_transition=None,
valid_custody_bits=None,
signed=False, signed=False,
on_time=True): on_time=True):
# If filter_participant_set filters everything, the attestation has 0 participants, and cannot be signed. # If filter_participant_set filters everything, the attestation has 0 participants, and cannot be signed.
@ -203,14 +163,6 @@ def get_valid_attestation(spec,
# fill the attestation with (optionally filtered) participants, and optionally sign it # fill the attestation with (optionally filtered) participants, and optionally sign it
fill_aggregate_attestation(spec, state, attestation, signed=signed, filter_participant_set=filter_participant_set) fill_aggregate_attestation(spec, state, attestation, signed=signed, filter_participant_set=filter_participant_set)
if spec.fork == PHASE1 and on_time:
attestation = convert_to_valid_on_time_attestation(
spec, state, attestation,
shard_transition,
valid_custody_bits=valid_custody_bits,
signed=signed,
)
return attestation return attestation
@ -230,43 +182,9 @@ def sign_aggregate_attestation(spec, state, attestation_data, participants: List
def sign_indexed_attestation(spec, state, indexed_attestation): def sign_indexed_attestation(spec, state, indexed_attestation):
if spec.fork == PHASE0: participants = indexed_attestation.attesting_indices
participants = indexed_attestation.attesting_indices data = indexed_attestation.data
data = indexed_attestation.data indexed_attestation.signature = sign_aggregate_attestation(spec, state, data, participants)
indexed_attestation.signature = sign_aggregate_attestation(spec, state, data, participants)
else:
participants = spec.get_indices_from_committee(
indexed_attestation.committee,
indexed_attestation.attestation.aggregation_bits,
)
data = indexed_attestation.attestation.data
if any(indexed_attestation.attestation.custody_bits_blocks):
sign_on_time_attestation(spec, state, indexed_attestation.attestation)
else:
indexed_attestation.attestation.signature = sign_aggregate_attestation(spec, state, data, participants)
def sign_on_time_attestation(spec, state, attestation):
if not any(attestation.custody_bits_blocks):
sign_attestation(spec, state, attestation)
return
committee = spec.get_beacon_committee(state, attestation.data.slot, attestation.data.index)
signatures = []
for block_index, custody_bits in enumerate(attestation.custody_bits_blocks):
for participant, abit, cbit in zip(committee, attestation.aggregation_bits, custody_bits):
if not abit:
continue
signatures.append(get_attestation_custody_signature(
spec,
state,
attestation.data,
block_index,
cbit,
privkeys[participant]
))
attestation.signature = bls.Aggregate(signatures)
def get_attestation_custody_signature(spec, state, attestation_data, block_index, bit, privkey): def get_attestation_custody_signature(spec, state, attestation_data, block_index, bit, privkey):
@ -283,10 +201,6 @@ def get_attestation_custody_signature(spec, state, attestation_data, block_index
def sign_attestation(spec, state, attestation): def sign_attestation(spec, state, attestation):
if spec.fork == PHASE1 and any(attestation.custody_bits_blocks):
sign_on_time_attestation(spec, state, attestation)
return
participants = spec.get_attesting_indices( participants = spec.get_attesting_indices(
state, state,
attestation.data, attestation.data,

View File

@ -1,4 +1,3 @@
from eth2spec.test.context import PHASE1
from eth2spec.test.helpers.attestations import get_valid_attestation, sign_attestation, sign_indexed_attestation from eth2spec.test.helpers.attestations import get_valid_attestation, sign_attestation, sign_indexed_attestation
@ -41,34 +40,19 @@ def get_indexed_attestation_participants(spec, indexed_att):
""" """
Wrapper around index-attestation to return the list of participant indices, regardless of spec phase. Wrapper around index-attestation to return the list of participant indices, regardless of spec phase.
""" """
if spec.fork == PHASE1: return list(indexed_att.attesting_indices)
return list(spec.get_indices_from_committee(
indexed_att.committee,
indexed_att.attestation.aggregation_bits,
))
else:
return list(indexed_att.attesting_indices)
def set_indexed_attestation_participants(spec, indexed_att, participants): def set_indexed_attestation_participants(spec, indexed_att, participants):
""" """
Wrapper around index-attestation to return the list of participant indices, regardless of spec phase. Wrapper around index-attestation to return the list of participant indices, regardless of spec phase.
""" """
if spec.fork == PHASE1: indexed_att.attesting_indices = participants
indexed_att.attestation.aggregation_bits = [bool(i in participants) for i in indexed_att.committee]
else:
indexed_att.attesting_indices = participants
def get_attestation_1_data(spec, att_slashing): def get_attestation_1_data(spec, att_slashing):
if spec.fork == PHASE1: return att_slashing.attestation_1.data
return att_slashing.attestation_1.attestation.data
else:
return att_slashing.attestation_1.data
def get_attestation_2_data(spec, att_slashing): def get_attestation_2_data(spec, att_slashing):
if spec.fork == PHASE1: return att_slashing.attestation_2.data
return att_slashing.attestation_2.attestation.data
else:
return att_slashing.attestation_2.data

View File

@ -59,7 +59,7 @@ def bitlist_from_int(max_len, num_bits, n):
return Bitlist[max_len](*[(n >> i) & 0b1 for i in range(num_bits)]) return Bitlist[max_len](*[(n >> i) & 0b1 for i in range(num_bits)])
def get_valid_custody_slashing(spec, state, attestation, shard_transition, invalid_custody_bit=False): def get_valid_custody_slashing(spec, state, attestation, shard_transition, custody_secret, data, data_index=0):
beacon_committee = spec.get_beacon_committee( beacon_committee = spec.get_beacon_committee(
state, state,
attestation.data.slot, attestation.data.slot,
@ -68,21 +68,10 @@ def get_valid_custody_slashing(spec, state, attestation, shard_transition, inval
malefactor_index = beacon_committee[0] malefactor_index = beacon_committee[0]
whistleblower_index = beacon_committee[-1] whistleblower_index = beacon_committee[-1]
epoch = spec.get_randao_epoch_for_custody_period(attestation.data.target.epoch,
malefactor_index)
# Generate the responder key
domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch)
signing_root = spec.compute_signing_root(spec.Epoch(epoch), domain)
malefactor_key = bls.Sign(privkeys[malefactor_index], signing_root)
data_index = 0
data = ByteList[spec.MAX_SHARD_BLOCK_SIZE](
get_custody_test_vector(shard_transition.shard_block_lengths[data_index]))
slashing = spec.CustodySlashing( slashing = spec.CustodySlashing(
data_index=data_index, data_index=data_index,
malefactor_index=malefactor_index, malefactor_index=malefactor_index,
malefactor_secret=malefactor_key, malefactor_secret=custody_secret,
whistleblower_index=whistleblower_index, whistleblower_index=whistleblower_index,
shard_transition=shard_transition, shard_transition=shard_transition,
attestation=attestation, attestation=attestation,
@ -165,9 +154,9 @@ def get_valid_custody_chunk_response(spec, state, chunk_challenge, block_length,
) )
def get_custody_test_vector(bytelength): def get_custody_test_vector(bytelength, offset=0):
ints = bytelength // 4 + 1 ints = bytelength // 4 + 1
return (b"".join(i.to_bytes(4, "little") for i in range(ints)))[:bytelength] return (b"".join((i + offset).to_bytes(4, "little") for i in range(ints)))[:bytelength]
def get_shard_transition(spec, start_slot, block_lengths): def get_shard_transition(spec, start_slot, block_lengths):
@ -181,3 +170,30 @@ def get_shard_transition(spec, start_slot, block_lengths):
proposer_signature_aggregate=spec.BLSSignature(), proposer_signature_aggregate=spec.BLSSignature(),
) )
return shard_transition return shard_transition
def get_custody_secret(spec, state, validator_index, epoch=None):
period = spec.get_custody_period_for_validator(validator_index, epoch if epoch is not None
else spec.get_current_epoch(state))
epoch_to_sign = spec.get_randao_epoch_for_custody_period(period, validator_index)
domain = spec.get_domain(state, spec.DOMAIN_RANDAO, epoch_to_sign)
signing_root = spec.compute_signing_root(spec.Epoch(epoch_to_sign), domain)
return bls.Sign(privkeys[validator_index], signing_root)
def get_custody_slashable_test_vector(spec, custody_secret, length, slashable=True):
test_vector = get_custody_test_vector(length)
offset = 0
while spec.compute_custody_bit(custody_secret, test_vector) != slashable:
offset += 1
test_vector = test_vector = get_custody_test_vector(length, offset)
return test_vector
def get_custody_slashable_shard_transition(spec, start_slot, block_lengths, custody_secret, slashable=True):
shard_transition = get_shard_transition(spec, start_slot, block_lengths)
slashable_test_vector = get_custody_slashable_test_vector(spec, custody_secret,
block_lengths[0], slashable=slashable)
block_data = ByteList[spec.MAX_SHARD_BLOCK_SIZE](slashable_test_vector)
shard_transition.shard_data_roots[0] = block_data.get_backing().get_left().merkle_root()
return shard_transition, slashable_test_vector

View File

@ -1,5 +1,5 @@
from eth2spec.test.context import ( from eth2spec.test.context import (
PHASE0, PHASE1, PHASE0,
spec_state_test, expect_assertion_error, always_bls, with_all_phases, with_phases spec_state_test, expect_assertion_error, always_bls, with_all_phases, with_phases
) )
from eth2spec.test.helpers.attestations import sign_indexed_attestation from eth2spec.test.helpers.attestations import sign_indexed_attestation
@ -162,10 +162,7 @@ def test_same_data(spec, state):
indexed_att_1 = attester_slashing.attestation_1 indexed_att_1 = attester_slashing.attestation_1
att_2_data = get_attestation_2_data(spec, attester_slashing) att_2_data = get_attestation_2_data(spec, attester_slashing)
if spec.fork == PHASE1: indexed_att_1.data = att_2_data
indexed_att_1.attestation.data = att_2_data
else:
indexed_att_1.data = att_2_data
sign_indexed_attestation(spec, state, attester_slashing.attestation_1) sign_indexed_attestation(spec, state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(spec, state, attester_slashing, False) yield from run_attester_slashing_processing(spec, state, attester_slashing, False)

View File

@ -25,22 +25,9 @@ def test_on_time_success(spec, state):
@with_all_phases_except(['phase0']) @with_all_phases_except(['phase0'])
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_on_time_empty_custody_bits_blocks(spec, state): def test_late_success(spec, state):
attestation = get_valid_late_attestation(spec, state, signed=True) attestation = get_valid_late_attestation(spec, state, signed=True)
assert not any(attestation.custody_bits_blocks)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases_except(['phase0'])
@spec_state_test
@always_bls
def test_late_with_custody_bits_blocks(spec, state):
attestation = get_valid_on_time_attestation(spec, state, signed=True)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY + 1) transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY + 1)
yield from run_attestation_processing(spec, state, attestation, False) yield from run_attestation_processing(spec, state, attestation)

View File

@ -1,6 +1,7 @@
from eth2spec.test.helpers.custody import ( from eth2spec.test.helpers.custody import (
get_valid_custody_slashing, get_valid_custody_slashing,
get_shard_transition, get_custody_secret,
get_custody_slashable_shard_transition,
) )
from eth2spec.test.helpers.attestations import ( from eth2spec.test.helpers.attestations import (
get_valid_on_time_attestation, get_valid_on_time_attestation,
@ -52,15 +53,39 @@ def run_custody_slashing_processing(spec, state, custody_slashing, valid=True, c
yield 'post', state yield 'post', state
@with_all_phases_except(['phase0']) def run_standard_custody_slashing_test(spec,
@spec_state_test state,
def test_custody_slashing(spec, state): shard_lateness=None,
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH) shard=None,
shard = 0 validator_index=None,
block_lengths=None,
slashing_message_data=None,
correct=True,
valid=True):
if shard_lateness is None:
shard_lateness = spec.SLOTS_PER_EPOCH
transition_to(spec, state, state.slot + shard_lateness)
if shard is None:
shard = 0
if validator_index is None:
validator_index = spec.get_beacon_committee(state, state.slot, shard)[0]
offset_slots = spec.get_offset_slots(state, shard) offset_slots = spec.get_offset_slots(state, shard)
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots)) if block_lengths is None:
block_lengths = [2**15 // 3] * len(offset_slots)
custody_secret = get_custody_secret(spec, state, validator_index)
shard_transition, slashable_test_vector = get_custody_slashable_shard_transition(
spec,
state.slot,
block_lengths,
custody_secret,
slashable=correct,
)
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True, attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True,
shard_transition=shard_transition, valid_custody_bits=False) shard_transition=shard_transition)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY) transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
@ -68,109 +93,45 @@ def test_custody_slashing(spec, state):
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1)) transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1))
slashing = get_valid_custody_slashing(spec, state, attestation, shard_transition) slashing = get_valid_custody_slashing(spec, state, attestation, shard_transition,
custody_secret, slashable_test_vector)
yield from run_custody_slashing_processing(spec, state, slashing, correct=True) if slashing_message_data is not None:
slashing.message.data = slashing_message_data
yield from run_custody_slashing_processing(spec, state, slashing, valid=valid, correct=correct)
@with_all_phases_except(['phase0'])
@spec_state_test
def test_custody_slashing(spec, state):
yield from run_standard_custody_slashing_test(spec, state)
@with_all_phases_except(['phase0']) @with_all_phases_except(['phase0'])
@spec_state_test @spec_state_test
def test_incorrect_custody_slashing(spec, state): def test_incorrect_custody_slashing(spec, state):
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH) yield from run_standard_custody_slashing_test(spec, state, correct=False)
shard = 0
offset_slots = spec.get_offset_slots(state, shard)
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots))
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True,
shard_transition=shard_transition, valid_custody_bits=True)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
_, _, _ = run_attestation_processing(spec, state, attestation)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1))
slashing = get_valid_custody_slashing(spec, state, attestation, shard_transition)
yield from run_custody_slashing_processing(spec, state, slashing, correct=False)
@with_all_phases_except(['phase0']) @with_all_phases_except(['phase0'])
@spec_state_test @spec_state_test
def test_multiple_epochs_custody(spec, state): def test_multiple_epochs_custody(spec, state):
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * 3) yield from run_standard_custody_slashing_test(spec, state, shard_lateness=spec.SLOTS_PER_EPOCH * 3)
shard = 0
offset_slots = spec.get_offset_slots(state, shard)
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots))
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True,
shard_transition=shard_transition, valid_custody_bits=False)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
_, _, _ = run_attestation_processing(spec, state, attestation)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1))
slashing = get_valid_custody_slashing(spec, state, attestation, shard_transition)
yield from run_custody_slashing_processing(spec, state, slashing, correct=True)
@with_all_phases_except(['phase0']) @with_all_phases_except(['phase0'])
@spec_state_test @spec_state_test
def test_many_epochs_custody(spec, state): def test_many_epochs_custody(spec, state):
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * 20) yield from run_standard_custody_slashing_test(spec, state, shard_lateness=spec.SLOTS_PER_EPOCH * 10)
shard = 0
offset_slots = spec.get_offset_slots(state, shard)
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots))
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True,
shard_transition=shard_transition, valid_custody_bits=False)
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
_, _, _ = run_attestation_processing(spec, state, attestation)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1))
slashing = get_valid_custody_slashing(spec, state, attestation, shard_transition)
yield from run_custody_slashing_processing(spec, state, slashing, correct=True)
@with_all_phases_except(['phase0'])
@spec_state_test
def test_off_chain_attestation(spec, state):
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH)
shard = 0
offset_slots = spec.get_offset_slots(state, shard)
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots))
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True,
shard_transition=shard_transition, valid_custody_bits=False)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1))
slashing = get_valid_custody_slashing(spec, state, attestation, shard_transition)
yield from run_custody_slashing_processing(spec, state, slashing, correct=True)
@with_all_phases_except(['phase0']) @with_all_phases_except(['phase0'])
@spec_state_test @spec_state_test
def test_invalid_custody_slashing(spec, state): def test_invalid_custody_slashing(spec, state):
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH) yield from run_standard_custody_slashing_test(
shard = 0 spec,
offset_slots = spec.get_offset_slots(state, shard) state,
shard_transition = get_shard_transition(spec, state.slot, [2**15 // 3] * len(offset_slots)) slashing_message_data=ByteList[spec.MAX_SHARD_BLOCK_SIZE](),
attestation = get_valid_on_time_attestation(spec, state, index=shard, signed=True, valid=False,
shard_transition=shard_transition, valid_custody_bits=False) )
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
_, _, _ = run_attestation_processing(spec, state, attestation)
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1))
slashing = get_valid_custody_slashing(spec, state, attestation, shard_transition)
slashing.message.data = ByteList[spec.MAX_SHARD_BLOCK_SIZE]()
yield from run_custody_slashing_processing(spec, state, slashing, valid=False)

View File

@ -1,12 +1,11 @@
from eth2spec.test.helpers.custody import ( from eth2spec.test.helpers.custody import (
get_valid_chunk_challenge, get_valid_chunk_challenge,
get_shard_transition, get_shard_transition,
get_valid_custody_key_reveal,
) )
from eth2spec.test.helpers.attestations import ( from eth2spec.test.helpers.attestations import (
get_valid_on_time_attestation, get_valid_on_time_attestation,
) )
from eth2spec.test.helpers.state import next_epoch_via_block, transition_to from eth2spec.test.helpers.state import transition_to
from eth2spec.test.context import ( from eth2spec.test.context import (
with_all_phases_except, with_all_phases_except,
spec_state_test, spec_state_test,
@ -17,7 +16,6 @@ from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_ep
from eth2spec.test.phase_1.block_processing.test_process_chunk_challenge import ( from eth2spec.test.phase_1.block_processing.test_process_chunk_challenge import (
run_chunk_challenge_processing, run_chunk_challenge_processing,
) )
from eth2spec.test.phase_1.block_processing.test_process_custody_key_reveal import run_custody_key_reveal_processing
def run_process_challenge_deadlines(spec, state): def run_process_challenge_deadlines(spec, state):
@ -44,32 +42,15 @@ def test_validator_slashed_after_chunk_challenge(spec, state):
attestation.data.index attestation.data.index
)[0] )[0]
spec.initiate_validator_exit(state, validator_index)
assert state.validators[validator_index].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH)
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_via_block(spec, state)
while (state.validators[validator_index].next_custody_secret_to_reveal
<= spec.get_custody_period_for_validator(
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_via_block(spec, state)
challenge = get_valid_chunk_challenge(spec, state, attestation, shard_transition) challenge = get_valid_chunk_challenge(spec, state, attestation, shard_transition)
_, _, _ = run_chunk_challenge_processing(spec, state, challenge) _, _, _ = run_chunk_challenge_processing(spec, state, challenge)
assert state.validators[validator_index].slashed == 0 assert state.validators[validator_index].slashed == 0
transition_to(spec, state, state.slot + (spec.CUSTODY_RESPONSE_DEADLINE + transition_to(spec, state, state.slot + spec.MAX_CHUNK_CHALLENGE_DELAY * spec.SLOTS_PER_EPOCH)
spec.EPOCHS_PER_CUSTODY_PERIOD) * spec.SLOTS_PER_EPOCH)
state.validators[validator_index].slashed = 0
yield from run_process_challenge_deadlines(spec, state) yield from run_process_challenge_deadlines(spec, state)

View File

@ -18,11 +18,13 @@ def run_process_challenge_deadlines(spec, state):
@spec_state_test @spec_state_test
def test_validator_slashed_after_reveal_deadline(spec, state): def test_validator_slashed_after_reveal_deadline(spec, state):
assert state.validators[0].slashed == 0 assert state.validators[0].slashed == 0
transition_to(spec, state, spec.get_randao_epoch_for_custody_period(0, 0) * spec.SLOTS_PER_EPOCH) transition_to(spec, state, spec.get_randao_epoch_for_custody_period(0, 0) * spec.SLOTS_PER_EPOCH)
transition_to(spec, state, state.slot + ((spec.CUSTODY_RESPONSE_DEADLINE) # Need to run at least one reveal so that not all validators are slashed (otherwise spec fails to find proposers)
* spec.SLOTS_PER_EPOCH)) custody_key_reveal = get_valid_custody_key_reveal(spec, state, validator_index=1)
_, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal)
transition_to(spec, state, state.slot + spec.EPOCHS_PER_CUSTODY_PERIOD * spec.SLOTS_PER_EPOCH)
state.validators[0].slashed = 0 state.validators[0].slashed = 0
@ -34,15 +36,14 @@ def test_validator_slashed_after_reveal_deadline(spec, state):
@with_all_phases_except(['phase0']) @with_all_phases_except(['phase0'])
@spec_state_test @spec_state_test
def test_validator_not_slashed_after_reveal(spec, state): def test_validator_not_slashed_after_reveal(spec, state):
state.slot += spec.EPOCHS_PER_CUSTODY_PERIOD * spec.SLOTS_PER_EPOCH transition_to(spec, state, spec.EPOCHS_PER_CUSTODY_PERIOD * spec.SLOTS_PER_EPOCH)
custody_key_reveal = get_valid_custody_key_reveal(spec, state) custody_key_reveal = get_valid_custody_key_reveal(spec, state)
_, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal) _, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal)
assert state.validators[0].slashed == 0 assert state.validators[0].slashed == 0
transition_to(spec, state, state.slot + ((spec.CUSTODY_RESPONSE_DEADLINE) transition_to(spec, state, state.slot + spec.EPOCHS_PER_CUSTODY_PERIOD * spec.SLOTS_PER_EPOCH)
* spec.SLOTS_PER_EPOCH))
yield from run_process_challenge_deadlines(spec, state) yield from run_process_challenge_deadlines(spec, state)