mirror of
https://github.com/ethereum/consensus-specs.git
synced 2026-02-02 03:15:11 -05:00
working through phase 1 attestation testing
This commit is contained in:
@@ -179,7 +179,7 @@ MAX_SHARD_BLOCK_CHUNKS: 4
|
||||
# 3 * 2**16` (= 196,608)
|
||||
TARGET_SHARD_BLOCK_SIZE: 196608
|
||||
# Note: MAX_SHARD_BLOCKS_PER_ATTESTATION is derived from the list length.
|
||||
SHARD_BLOCK_OFFSETS: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
|
||||
# SHARD_BLOCK_OFFSETS: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
|
||||
# len(SHARD_BLOCK_OFFSETS)
|
||||
MAX_SHARD_BLOCKS_PER_ATTESTATION: 12
|
||||
# 2**14 (= 16,384) Gwei
|
||||
|
||||
@@ -180,7 +180,7 @@ MAX_SHARD_BLOCK_CHUNKS: 4
|
||||
# 3 * 2**16` (= 196,608)
|
||||
TARGET_SHARD_BLOCK_SIZE: 196608
|
||||
# Note: MAX_SHARD_BLOCKS_PER_ATTESTATION is derived from the list length.
|
||||
SHARD_BLOCK_OFFSETS: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
|
||||
# SHARD_BLOCK_OFFSETS: [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
|
||||
# len(SHARD_BLOCK_OFFSETS)
|
||||
MAX_SHARD_BLOCKS_PER_ATTESTATION: 12
|
||||
# 2**14 (= 16,384) Gwei
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
- [`apply_shard_transition`](#apply_shard_transition)
|
||||
- [`process_crosslink_for_shard`](#process_crosslink_for_shard)
|
||||
- [`process_crosslinks`](#process_crosslinks)
|
||||
- [`process_attestations`](#process_attestations)
|
||||
- [`process_attestation`](#process_attestation)
|
||||
- [New Attester slashing processing](#new-attester-slashing-processing)
|
||||
- [Shard transition false positives](#shard-transition-false-positives)
|
||||
- [Light client processing](#light-client-processing)
|
||||
@@ -98,7 +98,7 @@ Configuration is not namespaced. Instead it is strictly an extension;
|
||||
| `SHARD_COMMITTEE_PERIOD` | `Epoch(2**8)` (= 256) | epochs | ~27 hours |
|
||||
| `MAX_SHARD_BLOCK_SIZE` | `2**20` (= 1,048,576) | |
|
||||
| `TARGET_SHARD_BLOCK_SIZE` | `2**18` (= 262,144) | |
|
||||
| `SHARD_BLOCK_OFFSETS` | `[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]` | |
|
||||
| `SHARD_BLOCK_OFFSETS` | `[0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]` | |
|
||||
| `MAX_SHARD_BLOCKS_PER_ATTESTATION` | `len(SHARD_BLOCK_OFFSETS)` | |
|
||||
| `MAX_GASPRICE` | `Gwei(2**14)` (= 16,384) | Gwei | |
|
||||
| `MIN_GASPRICE` | `Gwei(2**5)` (= 32) | Gwei | |
|
||||
@@ -500,7 +500,6 @@ def get_next_slot_for_shard(state: BeaconState, shard: Shard) -> Slot:
|
||||
return Slot(state.shard_states[shard].slot + 1)
|
||||
```
|
||||
|
||||
|
||||
#### `get_offset_slots`
|
||||
|
||||
```python
|
||||
@@ -526,7 +525,7 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
|
||||
domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch)
|
||||
aggregation_bits = attestation.aggregation_bits
|
||||
assert len(aggregation_bits) == len(indexed_attestation.committee)
|
||||
|
||||
|
||||
if len(attestation.custody_bits_blocks) == 0:
|
||||
# fall back on phase0 behavior if there is no shard data.
|
||||
for participant, abit in zip(indexed_attestation.committee, aggregation_bits):
|
||||
@@ -612,11 +611,9 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||
shard = get_shard(state, attestation)
|
||||
shard_start_slot = get_next_slot_for_shard(state, shard)
|
||||
|
||||
# Signature check
|
||||
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
|
||||
# Type 1: on-time attestations
|
||||
if attestation.custody_bits_blocks != []:
|
||||
# Correct slot
|
||||
# Ensure on-time attestation
|
||||
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY == state.slot
|
||||
# Correct data root count
|
||||
assert len(attestation.custody_bits_blocks) == len(get_offset_slots(state, shard_start_slot))
|
||||
@@ -624,8 +621,14 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||
assert data.beacon_block_root == get_block_root_at_slot(state, get_previous_slot(state.slot))
|
||||
# Type 2: no shard transition, no custody bits # TODO: could only allow for older attestations.
|
||||
else:
|
||||
# assert state.slot - compute_start_slot_at_epoch(compute_epoch_at_slot(data.slot)) < SLOTS_PER_EPOCH
|
||||
# Ensure delayed attestation
|
||||
# Currently commented out because breaks a ton of phase 0 tests
|
||||
# assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY < state.slot
|
||||
# Late attestations cannot have a shard transition root
|
||||
assert data.shard_transition_root == Root()
|
||||
|
||||
# Signature check
|
||||
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
|
||||
```
|
||||
|
||||
###### `apply_shard_transition`
|
||||
|
||||
@@ -1,11 +1,47 @@
|
||||
from typing import List
|
||||
|
||||
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
||||
from eth2spec.test.context import expect_assertion_error
|
||||
from eth2spec.test.helpers.keys import privkeys
|
||||
from eth2spec.utils import bls
|
||||
from eth2spec.utils.ssz.ssz_typing import Bitlist
|
||||
|
||||
|
||||
def run_attestation_processing(spec, state, attestation, valid=True):
|
||||
"""
|
||||
Run ``process_attestation``, yielding:
|
||||
- pre-state ('pre')
|
||||
- attestation ('attestation')
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
# yield pre-state
|
||||
yield 'pre', state
|
||||
|
||||
yield 'attestation', attestation
|
||||
|
||||
# If the attestation is invalid, processing is aborted, and there is no post-state.
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_attestation(state, attestation))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
current_epoch_count = len(state.current_epoch_attestations)
|
||||
previous_epoch_count = len(state.previous_epoch_attestations)
|
||||
|
||||
# process attestation
|
||||
spec.process_attestation(state, attestation)
|
||||
|
||||
# Make sure the attestation has been processed
|
||||
if attestation.data.target.epoch == spec.get_current_epoch(state):
|
||||
assert len(state.current_epoch_attestations) == current_epoch_count + 1
|
||||
else:
|
||||
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
|
||||
|
||||
# yield post-state
|
||||
yield 'post', state
|
||||
|
||||
|
||||
def build_attestation_data(spec, state, slot, index):
|
||||
assert state.slot >= slot
|
||||
|
||||
@@ -111,7 +147,6 @@ def get_attestation_signature(spec, state, attestation_data, privkey):
|
||||
|
||||
|
||||
def fill_aggregate_attestation(spec, state, attestation, signed=False):
|
||||
|
||||
beacon_committee = spec.get_beacon_committee(
|
||||
state,
|
||||
attestation.data.slot,
|
||||
|
||||
@@ -1,30 +1,66 @@
|
||||
from eth2spec.test.helpers.keys import privkeys
|
||||
from eth2spec.utils.ssz.ssz_typing import Bitlist
|
||||
from eth2spec.utils import bls
|
||||
|
||||
from eth2spec.test.helpers.keys import privkeys
|
||||
import eth2spec.test.helpers.attestations as phase0_attestations
|
||||
from eth2spec.test.helpers.state import next_slot
|
||||
|
||||
def sign_shard_attestation(spec, beacon_state, shard_state, block, participants):
|
||||
signatures = []
|
||||
message_hash = spec.ShardAttestationData(
|
||||
slot=block.slot,
|
||||
parent_root=block.parent_root,
|
||||
).hash_tree_root()
|
||||
block_epoch = spec.compute_epoch_of_shard_slot(block.slot)
|
||||
for validator_index in participants:
|
||||
privkey = privkeys[validator_index]
|
||||
signatures.append(
|
||||
get_attestation_signature(
|
||||
spec,
|
||||
beacon_state,
|
||||
shard_state,
|
||||
message_hash,
|
||||
block_epoch,
|
||||
privkey,
|
||||
)
|
||||
|
||||
def get_valid_on_time_attestation(spec, state, index=None, signed=False):
|
||||
'''
|
||||
Construct on-time attestation for next slot
|
||||
'''
|
||||
if index is None:
|
||||
index = 0
|
||||
|
||||
attestation = phase0_attestations.get_valid_attestation(spec, state, state.slot, index, False)
|
||||
shard = spec.get_shard(state, attestation)
|
||||
|
||||
next_state = state.copy()
|
||||
next_slot(spec, next_state)
|
||||
offset_slots = spec.get_offset_slots(next_state, spec.get_next_slot_for_shard(next_state, shard))
|
||||
for offset_slot in offset_slots:
|
||||
attestation.custody_bits_blocks.append(
|
||||
Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in attestation.aggregation_bits])
|
||||
)
|
||||
return bls.Aggregate(signatures)
|
||||
|
||||
if signed:
|
||||
sign_attestation(spec, state, attestation)
|
||||
|
||||
return attestation
|
||||
|
||||
|
||||
def get_attestation_signature(spec, beacon_state, shard_state, message_hash, block_epoch, privkey):
|
||||
domain = spec.get_domain(beacon_state, spec.DOMAIN_SHARD_ATTESTER, block_epoch)
|
||||
signing_root = spec.compute_signing_root(message_hash, domain)
|
||||
def sign_attestation(spec, state, attestation):
|
||||
if not any(attestation.custody_bits_blocks):
|
||||
phase0_attestations.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):
|
||||
domain = spec.get_domain(state, spec.DOMAIN_BEACON_ATTESTER, attestation_data.target.epoch)
|
||||
signing_root = spec.compute_signing_root(
|
||||
spec.AttestationCustodyBitWrapper(
|
||||
attestation_data.hash_tree_root(),
|
||||
block_index,
|
||||
bit,
|
||||
),
|
||||
domain,
|
||||
)
|
||||
return bls.Sign(privkey, signing_root)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
expect_assertion_error,
|
||||
always_bls, never_bls,
|
||||
with_all_phases,
|
||||
spec_test,
|
||||
@@ -8,6 +7,7 @@ from eth2spec.test.context import (
|
||||
with_custom_state,
|
||||
single_phase)
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
run_attestation_processing,
|
||||
get_valid_attestation,
|
||||
sign_aggregate_attestation,
|
||||
sign_attestation,
|
||||
@@ -19,41 +19,6 @@ from eth2spec.test.helpers.block import apply_empty_block
|
||||
from eth2spec.utils.ssz.ssz_typing import Bitlist
|
||||
|
||||
|
||||
def run_attestation_processing(spec, state, attestation, valid=True):
|
||||
"""
|
||||
Run ``process_attestation``, yielding:
|
||||
- pre-state ('pre')
|
||||
- attestation ('attestation')
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
# yield pre-state
|
||||
yield 'pre', state
|
||||
|
||||
yield 'attestation', attestation
|
||||
|
||||
# If the attestation is invalid, processing is aborted, and there is no post-state.
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_attestation(state, attestation))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
current_epoch_count = len(state.current_epoch_attestations)
|
||||
previous_epoch_count = len(state.previous_epoch_attestations)
|
||||
|
||||
# process attestation
|
||||
spec.process_attestation(state, attestation)
|
||||
|
||||
# Make sure the attestation has been processed
|
||||
if attestation.data.target.epoch == spec.get_current_epoch(state):
|
||||
assert len(state.current_epoch_attestations) == current_epoch_count + 1
|
||||
else:
|
||||
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
|
||||
|
||||
# yield post-state
|
||||
yield 'post', state
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_success(spec, state):
|
||||
|
||||
@@ -1,61 +1,26 @@
|
||||
from eth2spec.test.context import (
|
||||
with_all_phases_except,
|
||||
expect_assertion_error,
|
||||
spec_state_test,
|
||||
always_bls,
|
||||
)
|
||||
from eth2spec.test.helpers.state import next_slot, transition_to
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
get_valid_attestation,
|
||||
sign_attestation,
|
||||
run_attestation_processing,
|
||||
# get_valid_attestation as get_valid_late_attestation,
|
||||
)
|
||||
from eth2spec.test.helpers.phase1.attestations import (
|
||||
get_valid_on_time_attestation,
|
||||
)
|
||||
|
||||
from eth2spec.utils.ssz.ssz_typing import Bitlist
|
||||
|
||||
|
||||
def run_attestation_processing(spec, state, attestation, valid=True):
|
||||
"""
|
||||
Run ``process_attestation``, yielding:
|
||||
- pre-state ('pre')
|
||||
- attestation ('attestation')
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
# yield pre-state
|
||||
yield 'pre', state
|
||||
|
||||
yield 'attestation', attestation
|
||||
|
||||
# If the attestation is invalid, processing is aborted, and there is no post-state.
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_attestation(state, attestation))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
current_epoch_count = len(state.current_epoch_attestations)
|
||||
previous_epoch_count = len(state.previous_epoch_attestations)
|
||||
|
||||
# process attestation
|
||||
spec.process_attestation(state, attestation)
|
||||
|
||||
# Make sure the attestation has been processed
|
||||
if attestation.data.target.epoch == spec.get_current_epoch(state):
|
||||
assert len(state.current_epoch_attestations) == current_epoch_count + 1
|
||||
else:
|
||||
assert len(state.previous_epoch_attestations) == previous_epoch_count + 1
|
||||
|
||||
# yield post-state
|
||||
yield 'post', state
|
||||
|
||||
|
||||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_success_empty_custody_bits_blocks(spec, state):
|
||||
attestation = get_valid_attestation(spec, state)
|
||||
attestation.custody_bits_blocks = []
|
||||
sign_attestation(spec, state, attestation)
|
||||
def test_on_time_success(spec, state):
|
||||
next_slot(spec, state)
|
||||
attestation = get_valid_on_time_attestation(spec, state, signed=True)
|
||||
|
||||
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
|
||||
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
|
||||
@@ -63,18 +28,28 @@ def test_success_empty_custody_bits_blocks(spec, state):
|
||||
@with_all_phases_except(['phase0'])
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_fail_custody_bits_blocks_incorrect_slot(spec, state):
|
||||
attestation = get_valid_attestation(spec, state)
|
||||
committee = spec.get_beacon_committee(
|
||||
state,
|
||||
attestation.data.slot,
|
||||
attestation.data.index,
|
||||
)
|
||||
bitlist = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in range(len(committee))])
|
||||
bitlist[0] = 1
|
||||
attestation.custody_bits_blocks = [bitlist]
|
||||
sign_attestation(spec, state, attestation)
|
||||
def test_on_time_empty_custody_bits_blocks(spec, state):
|
||||
# Causing this test to pass causes many phase0 tests to fail
|
||||
pass
|
||||
"""
|
||||
next_slot(spec, state)
|
||||
attestation = get_valid_late_attestation(spec, state, signed=True)
|
||||
|
||||
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY + 1
|
||||
assert not any(attestation.custody_bits_blocks)
|
||||
|
||||
yield from run_attestation_processing(spec, state, attestation)
|
||||
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):
|
||||
next_slot(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)
|
||||
|
||||
Reference in New Issue
Block a user