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:
commit
eec323c7b6
|
@ -151,3 +151,9 @@ DOMAIN_DEPOSIT: 0x03000000
|
|||
DOMAIN_VOLUNTARY_EXIT: 0x04000000
|
||||
DOMAIN_SELECTION_PROOF: 0x05000000
|
||||
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
|
||||
|
|
|
@ -62,14 +62,26 @@ DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000
|
|||
# Time parameters
|
||||
# 2**1 (= 2) epochs, 12.8 minutes
|
||||
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
|
||||
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 16384
|
||||
# 2**11 (= 2,048) epochs, ~9 days
|
||||
EPOCHS_PER_CUSTODY_PERIOD: 2048
|
||||
EPOCHS_PER_CUSTODY_PERIOD: 16384
|
||||
# 2**11 (= 2,048) epochs, ~9 days
|
||||
CUSTODY_PERIOD_TO_RANDAO_PADDING: 2048
|
||||
# 2**14 (= 16,384) epochs
|
||||
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
|
||||
# 2**8 (= 256)
|
||||
|
|
|
@ -65,13 +65,27 @@ DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000
|
|||
# 2**1 (= 2) epochs
|
||||
RANDAO_PENALTY_EPOCHS: 2
|
||||
# [customized] quicker for testing
|
||||
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 4096
|
||||
EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS: 128
|
||||
# [customized] quicker for testing
|
||||
EPOCHS_PER_CUSTODY_PERIOD: 8
|
||||
EPOCHS_PER_CUSTODY_PERIOD: 64
|
||||
# [customized] quicker for testing
|
||||
CUSTODY_PERIOD_TO_RANDAO_PADDING: 8
|
||||
# [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
|
||||
# 2**8 (= 256)
|
||||
|
|
|
@ -53,15 +53,12 @@
|
|||
- [`get_shard_committee`](#get_shard_committee)
|
||||
- [`get_light_client_committee`](#get_light_client_committee)
|
||||
- [`get_shard_proposer_index`](#get_shard_proposer_index)
|
||||
- [`get_indexed_attestation`](#get_indexed_attestation)
|
||||
- [`get_committee_count_delta`](#get_committee_count_delta)
|
||||
- [`get_start_shard`](#get_start_shard)
|
||||
- [`get_shard`](#get_shard)
|
||||
- [`get_latest_slot_for_shard`](#get_latest_slot_for_shard)
|
||||
- [`get_offset_slots`](#get_offset_slots)
|
||||
- [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_winning_attestation`](#is_winning_attestation)
|
||||
- [`optional_aggregate_verify`](#optional_aggregate_verify)
|
||||
|
@ -78,7 +75,6 @@
|
|||
- [`verify_empty_shard_transition`](#verify_empty_shard_transition)
|
||||
- [`process_shard_transitions`](#process_shard_transitions)
|
||||
- [New default validator for deposits](#new-default-validator-for-deposits)
|
||||
- [New Attester slashing processing](#new-attester-slashing-processing)
|
||||
- [Light client processing](#light-client-processing)
|
||||
- [Epoch transition](#epoch-transition)
|
||||
- [Phase 1 final updates](#phase-1-final-updates)
|
||||
|
@ -186,7 +182,6 @@ class AttestationData(Container):
|
|||
class Attestation(Container):
|
||||
aggregation_bits: Bitlist[MAX_VALIDATORS_PER_COMMITTEE]
|
||||
data: AttestationData
|
||||
custody_bits_blocks: List[Bitlist[MAX_VALIDATORS_PER_COMMITTEE], MAX_SHARD_BLOCKS_PER_ATTESTATION]
|
||||
signature: BLSSignature
|
||||
```
|
||||
|
||||
|
@ -206,8 +201,9 @@ class PendingAttestation(Container):
|
|||
|
||||
```python
|
||||
class IndexedAttestation(Container):
|
||||
committee: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE]
|
||||
attestation: Attestation
|
||||
attesting_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE]
|
||||
data: AttestationData
|
||||
signature: BLSSignature
|
||||
```
|
||||
|
||||
### Extended `AttesterSlashing`
|
||||
|
@ -593,17 +589,6 @@ def get_shard_proposer_index(beacon_state: BeaconState, slot: Slot, shard: Shard
|
|||
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`
|
||||
|
||||
```python
|
||||
|
@ -673,65 +658,6 @@ def get_offset_slots(state: BeaconState, shard: Shard) -> Sequence[Slot]:
|
|||
|
||||
### 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`
|
||||
|
||||
```python
|
||||
|
@ -849,16 +775,11 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
|
|||
else:
|
||||
assert attestation.data.source == state.previous_justified_checkpoint
|
||||
|
||||
# Type 1: on-time attestations, the custody bits should be non-empty.
|
||||
if attestation.custody_bits_blocks != []:
|
||||
# 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))
|
||||
# Type 1: on-time attestations
|
||||
if is_on_time_attestation(state, attestation):
|
||||
# Correct parent block root
|
||||
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:
|
||||
# Ensure delayed attestation
|
||||
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
|
||||
|
||||
```python
|
||||
|
|
|
@ -60,6 +60,7 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
|
|||
| `CUSTODY_PRIME` | `2 ** 256 - 189` | - |
|
||||
| `CUSTODY_SECRETS` | `3` | - |
|
||||
| `BYTES_PER_CUSTODY_ATOM` | `32` | bytes |
|
||||
| `CUSTODY_PROBABILITY_EXPONENT` | `10` | - |
|
||||
|
||||
## Configuration
|
||||
|
||||
|
@ -68,11 +69,11 @@ This document details the beacon chain additions and changes in Phase 1 of Ether
|
|||
| Name | Value | Unit | Duration |
|
||||
| - | - | :-: | :-: |
|
||||
| `RANDAO_PENALTY_EPOCHS` | `2**1` (= 2) | epochs | 12.8 minutes |
|
||||
| `EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS` | `2**14` (= 16,384) | epochs | ~73 days |
|
||||
| `EPOCHS_PER_CUSTODY_PERIOD` | `2**11` (= 2,048) | epochs | ~9 days |
|
||||
| `EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS` | `2**15` (= 32,768) | epochs | ~146 days |
|
||||
| `EPOCHS_PER_CUSTODY_PERIOD` | `2**14` (= 16,384) | epochs | ~73 days |
|
||||
| `CUSTODY_PERIOD_TO_RANDAO_PADDING` | `2**11` (= 2,048) | epochs | ~9 days |
|
||||
| `MAX_CHUNK_CHALLENGE_DELAY` | `2**11` (= 2,048) | epochs | ~9 days |
|
||||
| `CUSTODY_RESPONSE_DEADLINE` | `2**14` (= 16,384) | epochs | ~73 days |
|
||||
| `MAX_CHUNK_CHALLENGE_DELAY` | `2**15` (= 32,768) | epochs | ~146 days |
|
||||
| `CHUNK_RESPONSE_DEADLINE` | `2**14` (= 16,384) | epochs | ~73 days |
|
||||
|
||||
### Max operations per block
|
||||
|
||||
|
@ -140,7 +141,6 @@ class CustodyChunkResponse(Container):
|
|||
|
||||
```python
|
||||
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.
|
||||
data_index: uint64
|
||||
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)
|
||||
secrets = get_custody_secrets(key)
|
||||
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`
|
||||
|
@ -517,9 +518,6 @@ def process_custody_slashing(state: BeaconState, signed_custody_slashing: Signed
|
|||
# Verify the 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.
|
||||
# Verify the shard transition is indeed attested by the attestation
|
||||
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)
|
||||
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
|
||||
computed_custody_bit = compute_custody_bit(custody_slashing.malefactor_secret, custody_slashing.data)
|
||||
|
||||
|
||||
# Verify the claim
|
||||
if claimed_custody_bit != computed_custody_bit:
|
||||
if computed_custody_bit == 1:
|
||||
# Slash the malefactor, reward the other committee members
|
||||
slash_validator(state, custody_slashing.malefactor_index)
|
||||
committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)
|
||||
others_count = len(committee) - 1
|
||||
whistleblower_reward = Gwei(malefactor.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT // others_count)
|
||||
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:
|
||||
epoch = get_current_epoch(state)
|
||||
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:
|
||||
slash_validator(state, ValidatorIndex(index))
|
||||
```
|
||||
|
@ -584,7 +578,7 @@ def process_reveal_deadlines(state: BeaconState) -> None:
|
|||
```python
|
||||
def process_challenge_deadlines(state: BeaconState) -> None:
|
||||
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)
|
||||
index_in_records = state.custody_chunk_challenge_records.index(custody_chunk_challenge)
|
||||
state.custody_chunk_challenge_records[index_in_records] = CustodyChunkChallengeRecord()
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Fork choice](#fork-choice)
|
||||
- [Helpers](#helpers)
|
||||
- [Extended `LatestMessage`](#extended-latestmessage)
|
||||
- [Updated `update_latest_messages`](#updated-update_latest_messages)
|
||||
- [Handlers](#handlers)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
@ -22,12 +20,6 @@
|
|||
|
||||
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
|
||||
|
||||
#### 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
|
||||
)
|
||||
```
|
||||
|
||||
### 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)
|
||||
```
|
||||
|
|
|
@ -16,18 +16,13 @@ def run_on_attestation(spec, state, store, attestation, valid=True):
|
|||
indexed_attestation = spec.get_indexed_attestation(state, attestation)
|
||||
spec.on_attestation(store, attestation)
|
||||
|
||||
sample_index = indexed_attestation.attesting_indices[0]
|
||||
if spec.fork == PHASE0:
|
||||
sample_index = indexed_attestation.attesting_indices[0]
|
||||
latest_message = spec.LatestMessage(
|
||||
epoch=attestation.data.target.epoch,
|
||||
root=attestation.data.beacon_block_root,
|
||||
)
|
||||
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(
|
||||
epoch=attestation.data.target.epoch,
|
||||
root=attestation.data.beacon_block_root,
|
||||
|
|
|
@ -2,14 +2,13 @@ from lru import LRU
|
|||
|
||||
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.block import build_empty_block_for_next_slot
|
||||
from eth2spec.test.helpers.shard_transitions import get_shard_transition_of_committee
|
||||
from eth2spec.test.helpers.keys import privkeys
|
||||
from eth2spec.utils import bls
|
||||
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):
|
||||
|
@ -97,44 +96,7 @@ def build_attestation_data(spec, state, slot, index, shard_transition=None, on_t
|
|||
return attestation_data
|
||||
|
||||
|
||||
def convert_to_valid_on_time_attestation(spec, state, attestation, shard_transition,
|
||||
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):
|
||||
def get_valid_on_time_attestation(spec, state, slot=None, index=None, shard_transition=None, signed=False):
|
||||
'''
|
||||
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,
|
||||
index=index,
|
||||
shard_transition=shard_transition,
|
||||
valid_custody_bits=valid_custody_bits,
|
||||
signed=signed,
|
||||
on_time=True,
|
||||
)
|
||||
|
@ -174,7 +135,6 @@ def get_valid_attestation(spec,
|
|||
index=None,
|
||||
filter_participant_set=None,
|
||||
shard_transition=None,
|
||||
valid_custody_bits=None,
|
||||
signed=False,
|
||||
on_time=True):
|
||||
# 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_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
|
||||
|
||||
|
||||
|
@ -230,43 +182,9 @@ def sign_aggregate_attestation(spec, state, attestation_data, participants: List
|
|||
|
||||
|
||||
def sign_indexed_attestation(spec, state, indexed_attestation):
|
||||
if spec.fork == PHASE0:
|
||||
participants = indexed_attestation.attesting_indices
|
||||
data = indexed_attestation.data
|
||||
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)
|
||||
participants = indexed_attestation.attesting_indices
|
||||
data = indexed_attestation.data
|
||||
indexed_attestation.signature = sign_aggregate_attestation(spec, state, data, participants)
|
||||
|
||||
|
||||
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):
|
||||
if spec.fork == PHASE1 and any(attestation.custody_bits_blocks):
|
||||
sign_on_time_attestation(spec, state, attestation)
|
||||
return
|
||||
|
||||
participants = spec.get_attesting_indices(
|
||||
state,
|
||||
attestation.data,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from eth2spec.test.context import PHASE1
|
||||
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.
|
||||
"""
|
||||
if spec.fork == PHASE1:
|
||||
return list(spec.get_indices_from_committee(
|
||||
indexed_att.committee,
|
||||
indexed_att.attestation.aggregation_bits,
|
||||
))
|
||||
else:
|
||||
return list(indexed_att.attesting_indices)
|
||||
return list(indexed_att.attesting_indices)
|
||||
|
||||
|
||||
def set_indexed_attestation_participants(spec, indexed_att, participants):
|
||||
"""
|
||||
Wrapper around index-attestation to return the list of participant indices, regardless of spec phase.
|
||||
"""
|
||||
if spec.fork == PHASE1:
|
||||
indexed_att.attestation.aggregation_bits = [bool(i in participants) for i in indexed_att.committee]
|
||||
else:
|
||||
indexed_att.attesting_indices = participants
|
||||
indexed_att.attesting_indices = participants
|
||||
|
||||
|
||||
def get_attestation_1_data(spec, att_slashing):
|
||||
if spec.fork == PHASE1:
|
||||
return att_slashing.attestation_1.attestation.data
|
||||
else:
|
||||
return att_slashing.attestation_1.data
|
||||
return att_slashing.attestation_1.data
|
||||
|
||||
|
||||
def get_attestation_2_data(spec, att_slashing):
|
||||
if spec.fork == PHASE1:
|
||||
return att_slashing.attestation_2.attestation.data
|
||||
else:
|
||||
return att_slashing.attestation_2.data
|
||||
return att_slashing.attestation_2.data
|
||||
|
|
|
@ -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)])
|
||||
|
||||
|
||||
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(
|
||||
state,
|
||||
attestation.data.slot,
|
||||
|
@ -68,21 +68,10 @@ def get_valid_custody_slashing(spec, state, attestation, shard_transition, inval
|
|||
malefactor_index = beacon_committee[0]
|
||||
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(
|
||||
data_index=data_index,
|
||||
malefactor_index=malefactor_index,
|
||||
malefactor_secret=malefactor_key,
|
||||
malefactor_secret=custody_secret,
|
||||
whistleblower_index=whistleblower_index,
|
||||
shard_transition=shard_transition,
|
||||
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
|
||||
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):
|
||||
|
@ -181,3 +170,30 @@ def get_shard_transition(spec, start_slot, block_lengths):
|
|||
proposer_signature_aggregate=spec.BLSSignature(),
|
||||
)
|
||||
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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from eth2spec.test.context import (
|
||||
PHASE0, PHASE1,
|
||||
PHASE0,
|
||||
spec_state_test, expect_assertion_error, always_bls, with_all_phases, with_phases
|
||||
)
|
||||
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
|
||||
att_2_data = get_attestation_2_data(spec, attester_slashing)
|
||||
if spec.fork == PHASE1:
|
||||
indexed_att_1.attestation.data = att_2_data
|
||||
else:
|
||||
indexed_att_1.data = att_2_data
|
||||
indexed_att_1.data = att_2_data
|
||||
sign_indexed_attestation(spec, state, attester_slashing.attestation_1)
|
||||
|
||||
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
|
||||
|
|
|
@ -25,22 +25,9 @@ def test_on_time_success(spec, state):
|
|||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
@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)
|
||||
|
||||
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)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation, False)
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from eth2spec.test.helpers.custody import (
|
||||
get_valid_custody_slashing,
|
||||
get_shard_transition,
|
||||
get_custody_secret,
|
||||
get_custody_slashable_shard_transition,
|
||||
)
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
get_valid_on_time_attestation,
|
||||
|
@ -52,15 +53,39 @@ def run_custody_slashing_processing(spec, state, custody_slashing, valid=True, c
|
|||
yield 'post', state
|
||||
|
||||
|
||||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
def test_custody_slashing(spec, state):
|
||||
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH)
|
||||
shard = 0
|
||||
def run_standard_custody_slashing_test(spec,
|
||||
state,
|
||||
shard_lateness=None,
|
||||
shard=None,
|
||||
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)
|
||||
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,
|
||||
shard_transition=shard_transition, valid_custody_bits=False)
|
||||
shard_transition=shard_transition)
|
||||
|
||||
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))
|
||||
|
||||
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'])
|
||||
@spec_state_test
|
||||
def test_incorrect_custody_slashing(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=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)
|
||||
yield from run_standard_custody_slashing_test(spec, state, correct=False)
|
||||
|
||||
|
||||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
def test_multiple_epochs_custody(spec, state):
|
||||
transition_to(spec, state, state.slot + 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)
|
||||
yield from run_standard_custody_slashing_test(spec, state, shard_lateness=spec.SLOTS_PER_EPOCH * 3)
|
||||
|
||||
|
||||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
def test_many_epochs_custody(spec, state):
|
||||
transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * 20)
|
||||
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)
|
||||
yield from run_standard_custody_slashing_test(spec, state, shard_lateness=spec.SLOTS_PER_EPOCH * 10)
|
||||
|
||||
|
||||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
def test_invalid_custody_slashing(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.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)
|
||||
yield from run_standard_custody_slashing_test(
|
||||
spec,
|
||||
state,
|
||||
slashing_message_data=ByteList[spec.MAX_SHARD_BLOCK_SIZE](),
|
||||
valid=False,
|
||||
)
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
from eth2spec.test.helpers.custody import (
|
||||
get_valid_chunk_challenge,
|
||||
get_shard_transition,
|
||||
get_valid_custody_key_reveal,
|
||||
)
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
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 (
|
||||
with_all_phases_except,
|
||||
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 (
|
||||
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):
|
||||
|
@ -44,32 +42,15 @@ def test_validator_slashed_after_chunk_challenge(spec, state):
|
|||
attestation.data.index
|
||||
)[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)
|
||||
|
||||
_, _, _ = run_chunk_challenge_processing(spec, state, challenge)
|
||||
|
||||
assert state.validators[validator_index].slashed == 0
|
||||
|
||||
transition_to(spec, state, state.slot + (spec.CUSTODY_RESPONSE_DEADLINE +
|
||||
spec.EPOCHS_PER_CUSTODY_PERIOD) * spec.SLOTS_PER_EPOCH)
|
||||
transition_to(spec, state, state.slot + spec.MAX_CHUNK_CHALLENGE_DELAY * spec.SLOTS_PER_EPOCH)
|
||||
|
||||
state.validators[validator_index].slashed = 0
|
||||
|
||||
yield from run_process_challenge_deadlines(spec, state)
|
||||
|
||||
|
|
|
@ -18,11 +18,13 @@ def run_process_challenge_deadlines(spec, state):
|
|||
@spec_state_test
|
||||
def test_validator_slashed_after_reveal_deadline(spec, state):
|
||||
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, state.slot + ((spec.CUSTODY_RESPONSE_DEADLINE)
|
||||
* spec.SLOTS_PER_EPOCH))
|
||||
# Need to run at least one reveal so that not all validators are slashed (otherwise spec fails to find proposers)
|
||||
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
|
||||
|
||||
|
@ -34,15 +36,14 @@ def test_validator_slashed_after_reveal_deadline(spec, state):
|
|||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
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)
|
||||
|
||||
_, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal)
|
||||
|
||||
assert state.validators[0].slashed == 0
|
||||
|
||||
transition_to(spec, state, state.slot + ((spec.CUSTODY_RESPONSE_DEADLINE)
|
||||
* spec.SLOTS_PER_EPOCH))
|
||||
transition_to(spec, state, state.slot + spec.EPOCHS_PER_CUSTODY_PERIOD * spec.SLOTS_PER_EPOCH)
|
||||
|
||||
yield from run_process_challenge_deadlines(spec, state)
|
||||
|
||||
|
|
Loading…
Reference in New Issue