[squashed] shard chain updates wip

Fix wrong field names

Fix `build_attestation_data` and other PR feedback from Danny and
Terence

1. Rename `get_previous_slot` to `compute_previous_slot`
2. Break down `build_empty_block` into
`get_state_and_beacon_parent_root_at_slot`, use it in
`build_shard_block`
3. Set defult `slot` to `shard_state.slot + 1` in `build_shard_block`

Update `verify_shard_block_message`: check beacon_parent_root at fork
choice rule stage instead of state transition

Fix  `beacon-chain.md`

1. Fix typo `attestation.slot == state.slot` -> `attestation.data.slot == state.slot` in `is_winning_attestation`
2. Check `verify_shard_transition_false_positives` **after** `process_operations`
3. Fix `shard_attestations` filter in `process_crosslinks`: since attestations come from block, should use `attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY == state.slot`
4. [TBD] Allow empty `light_client_signature` to make the tests pass
5. [TBD] Add `is_shard_attestation`, filter out empty `ShardTransition()`

Rework `test_process_crosslink`

Add basic phase 1 `test_blocks`

Add more test cases

Revert `is_shard_attestation` and fix test cases backward compatibility.

Remove `test_process_beacon_block_no_shard_transition` and consider it as invalid case.
This commit is contained in:
Hsiao-Wei Wang 2020-04-28 11:28:21 +08:00
parent c8a473ba24
commit 524ba166d1
No known key found for this signature in database
GPG Key ID: 95B070122902DEA4
10 changed files with 352 additions and 131 deletions

View File

@ -33,7 +33,7 @@
- [`AttestationCustodyBitWrapper`](#attestationcustodybitwrapper) - [`AttestationCustodyBitWrapper`](#attestationcustodybitwrapper)
- [Helper functions](#helper-functions) - [Helper functions](#helper-functions)
- [Misc](#misc-1) - [Misc](#misc-1)
- [`get_previous_slot`](#get_previous_slot) - [`compute_previous_slot`](#compute_previous_slot)
- [`pack_compact_validator`](#pack_compact_validator) - [`pack_compact_validator`](#pack_compact_validator)
- [`unpack_compact_validator`](#unpack_compact_validator) - [`unpack_compact_validator`](#unpack_compact_validator)
- [`committee_to_compact_committee`](#committee_to_compact_committee) - [`committee_to_compact_committee`](#committee_to_compact_committee)
@ -52,6 +52,7 @@
- [`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)
- [`is_shard_attestation`](#is_shard_attestation)
- [`is_winning_attestation`](#is_winning_attestation) - [`is_winning_attestation`](#is_winning_attestation)
- [Updated `is_valid_indexed_attestation`](#updated-is_valid_indexed_attestation) - [Updated `is_valid_indexed_attestation`](#updated-is_valid_indexed_attestation)
- [Block processing](#block-processing) - [Block processing](#block-processing)
@ -369,10 +370,10 @@ class AttestationCustodyBitWrapper(Container):
### Misc ### Misc
#### `get_previous_slot` #### `compute_previous_slot`
```python ```python
def get_previous_slot(slot: Slot) -> Slot: def compute_previous_slot(slot: Slot) -> Slot:
if slot > 0: if slot > 0:
return Slot(slot - 1) return Slot(slot - 1)
else: else:
@ -556,6 +557,21 @@ def get_offset_slots(state: BeaconState, shard: Shard) -> Sequence[Slot]:
### Predicates ### Predicates
#### `is_shard_attestation`
```python
def is_shard_attestation(state: BeaconState,
attestation: Attestation,
committee_index: CommitteeIndex) -> bool:
if not (
attestation.data.index == committee_index
and attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY == state.slot
):
return False
return True
```
#### `is_winning_attestation` #### `is_winning_attestation`
```python ```python
@ -568,7 +584,7 @@ def is_winning_attestation(state: BeaconState,
``winning_root`` formed by ``committee_index`` committee at the current slot. ``winning_root`` formed by ``committee_index`` committee at the current slot.
""" """
return ( return (
attestation.slot == state.slot attestation.data.slot == state.slot
and attestation.data.index == committee_index and attestation.data.index == committee_index
and attestation.data.shard_transition_root == winning_root and attestation.data.shard_transition_root == winning_root
) )
@ -623,9 +639,9 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
process_block_header(state, block) process_block_header(state, block)
process_randao(state, block.body) process_randao(state, block.body)
process_eth1_data(state, block.body) process_eth1_data(state, block.body)
verify_shard_transition_false_positives(state, block.body)
process_light_client_signatures(state, block.body) process_light_client_signatures(state, block.body)
process_operations(state, block.body) process_operations(state, block.body)
verify_shard_transition_false_positives(state, block.body)
``` ```
#### Operations #### Operations
@ -684,7 +700,7 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
# Correct data root count # Correct data root count
assert len(attestation.custody_bits_blocks) == len(get_offset_slots(state, shard)) 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, get_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, no custody bits
else: else:
# Ensure delayed attestation # Ensure delayed attestation
@ -821,11 +837,12 @@ def process_crosslinks(state: BeaconState,
for committee_index in map(CommitteeIndex, range(committee_count)): for committee_index in map(CommitteeIndex, range(committee_count)):
shard = compute_shard_from_committee_index(state, committee_index, state.slot) shard = compute_shard_from_committee_index(state, committee_index, state.slot)
# All attestations in the block for this committee/shard and current slot # All attestations in the block for this committee/shard and current slot
shard_transition = shard_transitions[shard]
shard_attestations = [ shard_attestations = [
attestation for attestation in attestations attestation for attestation in attestations
if attestation.data.index == committee_index and attestation.data.slot == state.slot if is_shard_attestation(state, attestation, committee_index)
] ]
shard_transition = shard_transitions[shard]
winning_root = process_crosslink_for_shard(state, committee_index, shard_transition, shard_attestations) winning_root = process_crosslink_for_shard(state, committee_index, shard_transition, shard_attestations)
if winning_root != Root(): if winning_root != Root():
# Mark relevant pending attestations as creating a successful crosslink # Mark relevant pending attestations as creating a successful crosslink
@ -920,10 +937,14 @@ def process_light_client_signatures(state: BeaconState, block_body: BeaconBlockB
increase_balance(state, get_beacon_proposer_index(state), Gwei(total_reward // PROPOSER_REWARD_QUOTIENT)) increase_balance(state, get_beacon_proposer_index(state), Gwei(total_reward // PROPOSER_REWARD_QUOTIENT))
slot = get_previous_slot(state.slot) slot = compute_previous_slot(state.slot)
signing_root = compute_signing_root(get_block_root_at_slot(state, slot), signing_root = compute_signing_root(get_block_root_at_slot(state, slot),
get_domain(state, DOMAIN_LIGHT_CLIENT, compute_epoch_at_slot(slot))) get_domain(state, DOMAIN_LIGHT_CLIENT, compute_epoch_at_slot(slot)))
assert bls.FastAggregateVerify(signer_pubkeys, signing_root, signature=block_body.light_client_signature) if len(signer_pubkeys) == 0:
# TODO: Or disallow empty light_client_signature?
return
else:
assert bls.FastAggregateVerify(signer_pubkeys, signing_root, signature=block_body.light_client_signature)
``` ```
### Epoch transition ### Epoch transition

View File

@ -86,7 +86,6 @@ def verify_shard_block_message(beacon_state: BeaconState,
slot: Slot, slot: Slot,
shard: Shard) -> bool: shard: Shard) -> bool:
assert block.shard_parent_root == shard_state.latest_block_root assert block.shard_parent_root == shard_state.latest_block_root
assert block.beacon_parent_root == get_block_root_at_slot(beacon_state, slot)
assert block.slot == slot assert block.slot == slot
assert block.proposer_index == get_shard_proposer_index(beacon_state, slot, shard) assert block.proposer_index == get_shard_proposer_index(beacon_state, slot, shard)
assert 0 < len(block.body) <= MAX_SHARD_BLOCK_SIZE assert 0 < len(block.body) <= MAX_SHARD_BLOCK_SIZE
@ -124,7 +123,6 @@ def is_valid_fraud_proof(beacon_state: BeaconState,
subkey: BLSPubkey, subkey: BLSPubkey,
beacon_parent_block: BeaconBlock) -> bool: beacon_parent_block: BeaconBlock) -> bool:
# 1. Check if `custody_bits[offset_index][j] != generate_custody_bit(subkey, block_contents)` for any `j`. # 1. Check if `custody_bits[offset_index][j] != generate_custody_bit(subkey, block_contents)` for any `j`.
shard = get_shard(beacon_state, attestation)
custody_bits = attestation.custody_bits_blocks custody_bits = attestation.custody_bits_blocks
for j in range(custody_bits[offset_index]): for j in range(custody_bits[offset_index]):
if custody_bits[offset_index][j] != generate_custody_bit(subkey, block): if custody_bits[offset_index][j] != generate_custody_bit(subkey, block):
@ -133,6 +131,7 @@ def is_valid_fraud_proof(beacon_state: BeaconState,
# 2. Check if the shard state transition result is wrong between # 2. Check if the shard state transition result is wrong between
# `transition.shard_states[offset_index - 1]` to `transition.shard_states[offset_index]`. # `transition.shard_states[offset_index - 1]` to `transition.shard_states[offset_index]`.
if offset_index == 0: if offset_index == 0:
shard = get_shard(beacon_state, attestation)
shard_state = beacon_parent_block.shard_transitions[shard].shard_states[-1] shard_state = beacon_parent_block.shard_transitions[shard].shard_states[-1]
else: else:
shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here. shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here.

View File

@ -103,7 +103,7 @@ def upgrade_to_phase1(pre: phase0.BeaconState) -> BeaconState:
ShardState( ShardState(
slot=pre.slot, slot=pre.slot,
gasprice=MIN_GASPRICE, gasprice=MIN_GASPRICE,
data=Root(), transition_digest=Root(),
latest_block_root=Root(), latest_block_root=Root(),
) for i in range(INITIAL_ACTIVE_SHARDS) ) for i in range(INITIAL_ACTIVE_SHARDS)
), ),
@ -111,7 +111,7 @@ def upgrade_to_phase1(pre: phase0.BeaconState) -> BeaconState:
current_light_committee=CompactCommittee(), # computed after state creation current_light_committee=CompactCommittee(), # computed after state creation
next_light_committee=CompactCommittee(), next_light_committee=CompactCommittee(),
# Custody game # Custody game
custody_challenge_index=0, exposed_derived_secrets=[] * EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS,
# exposed_derived_secrets will fully default to zeroes # exposed_derived_secrets will fully default to zeroes
) )
next_epoch = Epoch(epoch + 1) next_epoch = Epoch(epoch + 1)

View File

@ -1,7 +1,7 @@
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, PHASE0, PHASE1
from eth2spec.test.helpers.state import state_transition_and_sign_block from eth2spec.test.helpers.state import state_transition_and_sign_block, next_slot, transition_to
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.keys import privkeys from eth2spec.test.helpers.keys import privkeys
from eth2spec.utils import bls from eth2spec.utils import bls
@ -43,7 +43,7 @@ def run_attestation_processing(spec, state, attestation, valid=True):
yield 'post', state yield 'post', state
def build_attestation_data(spec, state, slot, index, shard_transition=None): def build_attestation_data(spec, state, slot, index, shard_transition=None, on_time=True):
assert state.slot >= slot assert state.slot >= slot
if slot == state.slot: if slot == state.slot:
@ -66,28 +66,42 @@ def build_attestation_data(spec, state, slot, index, shard_transition=None):
source_epoch = state.current_justified_checkpoint.epoch source_epoch = state.current_justified_checkpoint.epoch
source_root = state.current_justified_checkpoint.root source_root = state.current_justified_checkpoint.root
if spec.fork == PHASE1 and shard_transition is not None: attestation_data = spec.AttestationData(
shard_transition_root = shard_transition.hash_tree_root()
head_shard_root = shard_transition.shard_data_roots[len(shard_transition.shard_data_roots) - 1]
else:
shard_transition_root = spec.Root()
head_shard_root = spec.Root()
return spec.AttestationData(
slot=slot, slot=slot,
index=index, index=index,
beacon_block_root=block_root, beacon_block_root=block_root,
source=spec.Checkpoint(epoch=source_epoch, root=source_root), source=spec.Checkpoint(epoch=source_epoch, root=source_root),
target=spec.Checkpoint(epoch=spec.compute_epoch_at_slot(slot), root=epoch_boundary_root), target=spec.Checkpoint(epoch=spec.compute_epoch_at_slot(slot), root=epoch_boundary_root),
head_shard_root=head_shard_root,
shard_transition_root=shard_transition_root,
) )
if spec.fork == PHASE1:
if shard_transition is not None:
lastest_shard_data_root_index = len(shard_transition.shard_data_roots) - 1
attestation_data.head_shard_root = shard_transition.shard_data_roots[lastest_shard_data_root_index]
attestation_data.shard_transition_root = shard_transition.hash_tree_root()
else:
# No shard transition
shard = spec.get_shard(state, spec.Attestation(data=attestation_data))
if on_time:
temp_state = state.copy()
next_slot(spec, temp_state)
shard_transition = spec.get_shard_transition(temp_state, shard, [])
lastest_shard_data_root_index = len(shard_transition.shard_data_roots) - 1
attestation_data.head_shard_root = shard_transition.shard_data_roots[lastest_shard_data_root_index]
attestation_data.shard_transition_root = shard_transition.hash_tree_root()
else:
attestation_data.head_shard_root = state.shard_states[shard].transition_digest
attestation_data.shard_transition_root = spec.Root()
return attestation_data
def convert_to_valid_on_time_attestation(spec, state, attestation, signed=False): def convert_to_valid_on_time_attestation(spec, state, attestation, signed=False):
shard = spec.get_shard(state, attestation) shard = spec.get_shard(state, attestation)
offset_slots = spec.compute_offset_slots(spec.get_latest_slot_for_shard(state, shard), state.slot + 1) offset_slots = spec.compute_offset_slots(
for offset_slot in offset_slots: spec.get_latest_slot_for_shard(state, shard),
attestation.data.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY,
)
for _ in offset_slots:
attestation.custody_bits_blocks.append( attestation.custody_bits_blocks.append(
Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in attestation.aggregation_bits]) Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE]([0 for _ in attestation.aggregation_bits])
) )
@ -143,7 +157,9 @@ def get_valid_attestation(spec,
if index is None: if index is None:
index = 0 index = 0
attestation_data = build_attestation_data(spec, state, slot=slot, index=index, shard_transition=shard_transition) attestation_data = build_attestation_data(
spec, state, slot=slot, index=index, shard_transition=shard_transition, on_time=on_time
)
beacon_committee = spec.get_beacon_committee( beacon_committee = spec.get_beacon_committee(
state, state,
@ -298,7 +314,21 @@ def next_epoch_with_attestations(spec,
spec, post_state, slot_to_attest, index=index, signed=True, on_time=False) spec, post_state, slot_to_attest, index=index, signed=True, on_time=False)
block.body.attestations.append(prev_attestation) block.body.attestations.append(prev_attestation)
if spec.fork == PHASE1:
fill_block_shard_transitions_by_attestations(spec, post_state, block)
signed_block = state_transition_and_sign_block(spec, post_state, block) signed_block = state_transition_and_sign_block(spec, post_state, block)
signed_blocks.append(signed_block) signed_blocks.append(signed_block)
return state, signed_blocks, post_state return state, signed_blocks, post_state
def fill_block_shard_transitions_by_attestations(spec, state, block):
block.body.shard_transitions = [spec.ShardTransition()] * spec.MAX_SHARDS
for attestation in block.body.attestations:
shard = spec.get_shard(state, attestation)
if attestation.data.slot == state.slot:
temp_state = state.copy()
transition_to(spec, temp_state, slot=block.slot)
shard_transition = spec.get_shard_transition(temp_state, shard, [])
block.body.shard_transitions[shard] = shard_transition

View File

@ -71,24 +71,31 @@ def build_empty_block(spec, state, slot=None):
""" """
if slot is None: if slot is None:
slot = state.slot slot = state.slot
if slot < state.slot:
raise Exception("build_empty_block cannot build blocks for past slots")
if slot > state.slot:
# transition forward in copied state to grab relevant data from state
state = state.copy()
spec.process_slots(state, slot)
state, parent_block_root = get_state_and_beacon_parent_root_at_slot(spec, state, slot)
empty_block = spec.BeaconBlock() empty_block = spec.BeaconBlock()
empty_block.slot = slot empty_block.slot = slot
empty_block.proposer_index = spec.get_beacon_proposer_index(state) empty_block.proposer_index = spec.get_beacon_proposer_index(state)
empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index
previous_block_header = state.latest_block_header.copy() empty_block.parent_root = parent_block_root
if previous_block_header.state_root == spec.Root():
previous_block_header.state_root = hash_tree_root(state)
empty_block.parent_root = hash_tree_root(previous_block_header)
apply_randao_reveal(spec, state, empty_block) apply_randao_reveal(spec, state, empty_block)
return empty_block return empty_block
def build_empty_block_for_next_slot(spec, state): def build_empty_block_for_next_slot(spec, state):
return build_empty_block(spec, state, state.slot + 1) return build_empty_block(spec, state, state.slot + 1)
def get_state_and_beacon_parent_root_at_slot(spec, state, slot):
if slot < state.slot:
raise Exception("Cannot build blocks for past slots")
if slot > state.slot:
# transition forward in copied state to grab relevant data from state
state = state.copy()
spec.process_slots(state, slot)
previous_block_header = state.latest_block_header.copy()
if previous_block_header.state_root == spec.Root():
previous_block_header.state_root = hash_tree_root(state)
beacon_parent_root = hash_tree_root(previous_block_header)
return state, beacon_parent_root

View File

@ -1,3 +1,6 @@
from eth2spec.test.helpers.attestations import get_valid_on_time_attestation
from eth2spec.test.helpers.block import get_state_and_beacon_parent_root_at_slot
from eth2spec.test.helpers.state import next_slots
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.bls import only_with_bls from eth2spec.utils.bls import only_with_bls
@ -18,21 +21,22 @@ def sign_shard_block(spec, beacon_state, shard, block, proposer_index=None):
def build_shard_block(spec, def build_shard_block(spec,
beacon_state, beacon_state,
shard, shard,
slot, slot=None,
body=None, body=None,
signed=False): signed=False):
shard_state = beacon_state.shard_states[shard] shard_state = beacon_state.shard_states[shard]
if slot is None: if slot is None:
slot = shard_state.slot slot = shard_state.slot + 1
if body is None: if body is None:
body = [] body = b'\x56' * 128
proposer_index = spec.get_shard_proposer_index(beacon_state, slot, shard) proposer_index = spec.get_shard_proposer_index(beacon_state, slot, shard)
beacon_state, beacon_parent_root = get_state_and_beacon_parent_root_at_slot(spec, beacon_state, slot)
block = spec.ShardBlock( block = spec.ShardBlock(
shard_parent_root=shard_state.latest_block_root, shard_parent_root=shard_state.latest_block_root,
beacon_parent_root=spec.get_block_root_at_slot(beacon_state, spec.get_previous_slot(slot)), beacon_parent_root=beacon_parent_root,
slot=slot, slot=slot,
proposer_index=proposer_index, proposer_index=proposer_index,
body=body, body=body,
@ -45,3 +49,40 @@ def build_shard_block(spec,
sign_shard_block(spec, beacon_state, shard, signed_block, proposer_index=proposer_index) sign_shard_block(spec, beacon_state, shard, signed_block, proposer_index=proposer_index)
return signed_block return signed_block
def build_shard_transitions_till_slot(spec, state, shards, shard_blocks, target_len_offset_slot):
state = state.copy()
next_slots(spec, state, target_len_offset_slot)
shard_transitions = [spec.ShardTransition()] * spec.MAX_SHARDS
for shard in shards:
offset_slots = spec.get_offset_slots(state, shard)
len_offset_slots = len(offset_slots)
assert len_offset_slots == target_len_offset_slot
shard_blocks_of_shard = shard_blocks[shard]
shard_transition = spec.get_shard_transition(state, shard, shard_blocks_of_shard)
if len(shard_blocks_of_shard) > 0:
shard_block_root = shard_blocks_of_shard[-1].message.hash_tree_root()
assert shard_transition.shard_states[len_offset_slots - 1].latest_block_root == shard_block_root
assert shard_transition.shard_states[len_offset_slots - 1].slot == offset_slots[-1]
shard_transitions[shard] = shard_transition
return shard_transitions
def build_attestation_with_shard_transition(spec, state, slot, index, target_len_offset_slot, shard_transition=None):
state = state.copy()
next_slots(spec, state, target_len_offset_slot)
attestation = get_valid_on_time_attestation(
spec,
state,
slot=slot,
index=index,
shard_transition=shard_transition,
signed=True,
)
assert attestation.data.slot == slot
if shard_transition is not None:
assert target_len_offset_slot == len(shard_transition.shard_states)
assert attestation.data.shard_transition_root == shard_transition.hash_tree_root()
return attestation

View File

@ -8,10 +8,13 @@ from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_e
from eth2spec.test.helpers.keys import privkeys, pubkeys from eth2spec.test.helpers.keys import privkeys, pubkeys
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, get_indexed_attestation_participants from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, get_indexed_attestation_participants
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
from eth2spec.test.helpers.attestations import get_valid_attestation from eth2spec.test.helpers.attestations import get_valid_attestation, fill_block_shard_transitions_by_attestations
from eth2spec.test.helpers.deposits import prepare_state_and_deposit from eth2spec.test.helpers.deposits import prepare_state_and_deposit
from eth2spec.test.context import spec_state_test, with_all_phases, expect_assertion_error, always_bls, with_phases from eth2spec.test.context import (
spec_state_test, with_all_phases, expect_assertion_error, always_bls, with_phases,
PHASE1
)
@with_all_phases @with_all_phases
@ -420,12 +423,14 @@ def test_attestation(spec, state):
yield 'pre', state yield 'pre', state
attestation = get_valid_attestation(spec, state, signed=True) attestation = get_valid_attestation(spec, state, signed=True, on_time=True)
# Add to state via block transition # Add to state via block transition
pre_current_attestations_len = len(state.current_epoch_attestations) pre_current_attestations_len = len(state.current_epoch_attestations)
attestation_block = build_empty_block(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY) attestation_block = build_empty_block(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
attestation_block.body.attestations.append(attestation) attestation_block.body.attestations.append(attestation)
if spec.fork == PHASE1:
fill_block_shard_transitions_by_attestations(spec, state, attestation_block)
signed_attestation_block = state_transition_and_sign_block(spec, state, attestation_block) signed_attestation_block = state_transition_and_sign_block(spec, state, attestation_block)
assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1 assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1

View File

@ -1,101 +1,78 @@
from eth2spec.test.context import ( from eth2spec.test.context import (
PHASE0,
with_all_phases_except, with_all_phases_except,
spec_state_test, spec_state_test,
always_bls, always_bls,
) )
from eth2spec.test.helpers.attestations import ( from eth2spec.test.helpers.crosslinks import run_crosslinks_processing
get_valid_on_time_attestation, from eth2spec.test.helpers.shard_block import (
build_attestation_with_shard_transition,
build_shard_block,
build_shard_transitions_till_slot,
) )
from eth2spec.test.helpers.crosslinks import ( from eth2spec.test.helpers.state import next_epoch, next_slot, transition_to
run_crosslinks_processing,
)
from eth2spec.test.helpers.shard_block import build_shard_block
from eth2spec.test.helpers.state import next_epoch, next_slot, next_slots
@with_all_phases_except(['phase0']) def run_basic_crosslink_tests(spec, state, target_len_offset_slot):
next_epoch(spec, state)
next_epoch(spec, state)
state = spec.upgrade_to_phase1(state)
next_slot(spec, state)
# At the beginning, let `x = state.slot`, `state.shard_states[shard].slot == x - 1`
slot_x = state.slot
committee_index = spec.CommitteeIndex(0)
shard = spec.compute_shard_from_committee_index(state, committee_index, state.slot)
assert state.shard_states[shard].slot == slot_x - 1
# Create SignedShardBlock at slot `shard_state.slot + 1` -> x
body = b'\x56' * spec.MAX_SHARD_BLOCK_SIZE
shard_block = build_shard_block(spec, state, shard, body=body, signed=True)
shard_blocks = [shard_block]
# Attester creates `attestation` at slot x
# Use temporary next state to get ShardTransition of shard block
shard_transitions = build_shard_transitions_till_slot(
spec,
state,
shards=[shard, ],
shard_blocks={shard: shard_blocks},
target_len_offset_slot=target_len_offset_slot,
)
shard_transition = shard_transitions[shard]
attestation = build_attestation_with_shard_transition(
spec,
state,
slot=slot_x + target_len_offset_slot - 1,
index=committee_index,
target_len_offset_slot=target_len_offset_slot,
shard_transition=shard_transition,
)
pre_gasprice = state.shard_states[shard].gasprice
transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)
pre_shard_state = state.shard_states[shard]
yield from run_crosslinks_processing(spec, state, shard_transitions, [attestation])
# After state transition,
assert state.slot == slot_x + target_len_offset_slot
shard_state = state.shard_states[shard]
assert shard_state != pre_shard_state
assert shard_state == shard_transition.shard_states[len(shard_transition.shard_states) - 1]
if target_len_offset_slot == 1:
assert shard_state.gasprice > pre_gasprice
@with_all_phases_except([PHASE0])
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_basic_crosslinks(spec, state): def test_basic_crosslinks(spec, state):
next_epoch(spec, state) run_basic_crosslink_tests(spec, state, target_len_offset_slot=1)
next_epoch(spec, state)
state = spec.upgrade_to_phase1(state)
next_slot(spec, state)
committee_index = spec.CommitteeIndex(0)
shard = spec.compute_shard_from_committee_index(state, committee_index, state.slot)
body = b'1' * spec.MAX_SHARD_BLOCK_SIZE
shard_block = build_shard_block(spec, state, shard, body=body, slot=state.slot, signed=True)
shard_blocks = [shard_block]
next_slot(spec, state)
shard_transition = spec.get_shard_transition(state, shard, shard_blocks)
shard_transitions = [spec.ShardTransition()] * len(state.shard_states)
shard_transitions[shard] = shard_transition
attestation = get_valid_on_time_attestation(
spec,
state,
slot=state.slot,
index=committee_index,
shard_transition=shard_transition,
signed=True,
)
attestations = [attestation]
pre_gasprice = state.shard_states[shard].gasprice
offset_slots = spec.get_offset_slots(state, shard)
assert len(offset_slots) == 1
yield from run_crosslinks_processing(spec, state, shard_transitions, attestations)
shard_state = state.shard_states[shard]
assert shard_state.slot == offset_slots[-1]
assert shard_state.latest_block_root == shard_block.message.hash_tree_root()
assert shard_state == shard_transition.shard_states[len(shard_transition.shard_states) - 1]
assert shard_state.gasprice > pre_gasprice
@with_all_phases_except(['phase0']) @with_all_phases_except([PHASE0])
@spec_state_test @spec_state_test
@always_bls @always_bls
def test_multiple_offset_slots(spec, state): def test_multiple_offset_slots(spec, state):
next_epoch(spec, state) run_basic_crosslink_tests(spec, state, target_len_offset_slot=3)
next_epoch(spec, state)
state = spec.upgrade_to_phase1(state)
next_slot(spec, state)
committee_index = spec.CommitteeIndex(0)
shard = spec.compute_shard_from_committee_index(state, committee_index, state.slot)
body = b'1' * spec.MAX_SHARD_BLOCK_SIZE
shard_block = build_shard_block(spec, state, shard, body=body, slot=state.slot, signed=True)
shard_blocks = [shard_block]
next_slots(spec, state, 3)
shard_transition = spec.get_shard_transition(state, shard, shard_blocks)
shard_transitions = [spec.ShardTransition()] * len(state.shard_states)
shard_transitions[shard] = shard_transition
attestation = get_valid_on_time_attestation(
spec,
state,
slot=state.slot,
index=committee_index,
shard_transition=shard_transition,
signed=True,
)
attestations = [attestation]
pre_gasprice = state.shard_states[shard].gasprice
offset_slots = spec.get_offset_slots(state, shard)
assert len(offset_slots) == 3
yield from run_crosslinks_processing(spec, state, shard_transitions, attestations)
shard_state = state.shard_states[shard]
assert shard_state.slot == offset_slots[-1]
assert shard_state.latest_block_root == shard_block.message.hash_tree_root()
assert shard_state == shard_transition.shard_states[len(shard_transition.shard_states) - 1]
assert shard_state.gasprice > pre_gasprice

View File

@ -0,0 +1,141 @@
from eth2spec.test.context import (
PHASE0,
with_all_phases_except,
spec_state_test,
always_bls,
)
from eth2spec.test.helpers.block import build_empty_block
from eth2spec.test.helpers.shard_block import (
build_attestation_with_shard_transition,
build_shard_block,
build_shard_transitions_till_slot,
)
from eth2spec.test.helpers.state import next_epoch, next_slot, state_transition_and_sign_block
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_process_beacon_block_with_normal_shard_transition(spec, state):
next_epoch(spec, state)
next_epoch(spec, state)
state = spec.upgrade_to_phase1(state)
next_slot(spec, state)
target_len_offset_slot = 1
# At the beginning, let `x = state.slot`, `state.shard_states[shard].slot == x - 1`
slot_x = state.slot
committee_index = spec.CommitteeIndex(0)
shard = spec.compute_shard_from_committee_index(state, committee_index, state.slot)
assert state.shard_states[shard].slot == slot_x - 1
# Create SignedShardBlock at slot `shard_state.slot + 1` -> x
body = b'\x56' * spec.MAX_SHARD_BLOCK_SIZE
shard_block = build_shard_block(spec, state, shard, body=body, signed=True)
shard_blocks = [shard_block]
# Attester creates `attestation` at slot x
# Use temporary next state to get ShardTransition of shard block
shard_transitions = build_shard_transitions_till_slot(
spec,
state,
shards=[shard, ],
shard_blocks={shard: shard_blocks},
target_len_offset_slot=target_len_offset_slot,
)
shard_transition = shard_transitions[shard]
attestation = build_attestation_with_shard_transition(
spec,
state,
slot=slot_x + target_len_offset_slot - 1,
index=committee_index,
target_len_offset_slot=target_len_offset_slot,
shard_transition=shard_transition,
)
pre_gasprice = state.shard_states[shard].gasprice
# Propose beacon block at slot `x + 1`
pre_shard_state = state.shard_states[shard]
beacon_block_1 = build_empty_block(spec, state, slot=slot_x + target_len_offset_slot)
beacon_block_1.body.attestations = [attestation]
beacon_block_1.body.shard_transitions = shard_transitions
assert (
beacon_block_1.slot == slot_x + target_len_offset_slot
== shard_transition.shard_states[0].slot + target_len_offset_slot
)
state_transition_and_sign_block(spec, state, beacon_block_1)
# After state transition
assert state.slot == slot_x + target_len_offset_slot
shard_state = state.shard_states[shard]
# latest_block_root has changed
assert shard_state.latest_block_root == shard_block.message.hash_tree_root()
assert shard_state != pre_shard_state
assert shard_state == shard_transition.shard_states[len(shard_transition.shard_states) - 1]
if target_len_offset_slot == 1 and len(shard_blocks) > 0:
assert shard_state.gasprice > pre_gasprice
@with_all_phases_except([PHASE0])
@spec_state_test
@always_bls
def test_process_beacon_block_with_empty_proposal_transition(spec, state):
next_epoch(spec, state)
next_epoch(spec, state)
state = spec.upgrade_to_phase1(state)
next_slot(spec, state)
target_len_offset_slot = 1
# At the beginning, let `x = state.slot`, `state.shard_states[shard].slot == x - 1`
slot_x = state.slot
committee_index = spec.CommitteeIndex(0)
shard = spec.compute_shard_from_committee_index(state, committee_index, state.slot)
assert state.shard_states[shard].slot == slot_x - 1
# No new shard block
shard_blocks = []
# Attester creates `attestation` at slot x
# Use temporary next state to get ShardTransition of shard block
shard_transitions = build_shard_transitions_till_slot(
spec,
state,
shards=[shard, ],
shard_blocks={shard: shard_blocks},
target_len_offset_slot=target_len_offset_slot,
)
shard_transition = shard_transitions[shard]
attestation = build_attestation_with_shard_transition(
spec,
state,
slot=slot_x + target_len_offset_slot - 1,
index=committee_index,
target_len_offset_slot=target_len_offset_slot,
shard_transition=shard_transition,
)
pre_gasprice = state.shard_states[shard].gasprice
# Propose beacon block at slot `x + 1`
pre_shard_state = state.shard_states[shard]
beacon_block_1 = build_empty_block(spec, state, slot=slot_x + target_len_offset_slot)
beacon_block_1.body.attestations = [attestation]
beacon_block_1.body.shard_transitions = shard_transitions
assert (
beacon_block_1.slot == slot_x + target_len_offset_slot
== shard_transition.shard_states[0].slot + target_len_offset_slot
)
state_transition_and_sign_block(spec, state, beacon_block_1)
# After state transition
assert state.slot == slot_x + target_len_offset_slot
shard_state = state.shard_states[shard]
# latest_block_root hasn't changed
assert shard_state.latest_block_root == pre_shard_state.latest_block_root
assert shard_state != pre_shard_state
assert shard_state == shard_transition.shard_states[len(shard_transition.shard_states) - 1]
if target_len_offset_slot == 1 and len(shard_blocks) > 0:
assert shard_state.gasprice > pre_gasprice