[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:
parent
c8a473ba24
commit
524ba166d1
|
@ -33,7 +33,7 @@
|
|||
- [`AttestationCustodyBitWrapper`](#attestationcustodybitwrapper)
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Misc](#misc-1)
|
||||
- [`get_previous_slot`](#get_previous_slot)
|
||||
- [`compute_previous_slot`](#compute_previous_slot)
|
||||
- [`pack_compact_validator`](#pack_compact_validator)
|
||||
- [`unpack_compact_validator`](#unpack_compact_validator)
|
||||
- [`committee_to_compact_committee`](#committee_to_compact_committee)
|
||||
|
@ -52,6 +52,7 @@
|
|||
- [`get_latest_slot_for_shard`](#get_latest_slot_for_shard)
|
||||
- [`get_offset_slots`](#get_offset_slots)
|
||||
- [Predicates](#predicates)
|
||||
- [`is_shard_attestation`](#is_shard_attestation)
|
||||
- [`is_winning_attestation`](#is_winning_attestation)
|
||||
- [Updated `is_valid_indexed_attestation`](#updated-is_valid_indexed_attestation)
|
||||
- [Block processing](#block-processing)
|
||||
|
@ -369,10 +370,10 @@ class AttestationCustodyBitWrapper(Container):
|
|||
|
||||
### Misc
|
||||
|
||||
#### `get_previous_slot`
|
||||
#### `compute_previous_slot`
|
||||
|
||||
```python
|
||||
def get_previous_slot(slot: Slot) -> Slot:
|
||||
def compute_previous_slot(slot: Slot) -> Slot:
|
||||
if slot > 0:
|
||||
return Slot(slot - 1)
|
||||
else:
|
||||
|
@ -556,6 +557,21 @@ def get_offset_slots(state: BeaconState, shard: Shard) -> Sequence[Slot]:
|
|||
|
||||
### 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`
|
||||
|
||||
```python
|
||||
|
@ -568,7 +584,7 @@ def is_winning_attestation(state: BeaconState,
|
|||
``winning_root`` formed by ``committee_index`` committee at the current slot.
|
||||
"""
|
||||
return (
|
||||
attestation.slot == state.slot
|
||||
attestation.data.slot == state.slot
|
||||
and attestation.data.index == committee_index
|
||||
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_randao(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_operations(state, block.body)
|
||||
verify_shard_transition_false_positives(state, block.body)
|
||||
```
|
||||
|
||||
#### Operations
|
||||
|
@ -684,7 +700,7 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None:
|
|||
# Correct data root count
|
||||
assert len(attestation.custody_bits_blocks) == len(get_offset_slots(state, shard))
|
||||
# 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
|
||||
else:
|
||||
# Ensure delayed attestation
|
||||
|
@ -821,11 +837,12 @@ def process_crosslinks(state: BeaconState,
|
|||
for committee_index in map(CommitteeIndex, range(committee_count)):
|
||||
shard = compute_shard_from_committee_index(state, committee_index, state.slot)
|
||||
# All attestations in the block for this committee/shard and current slot
|
||||
shard_transition = shard_transitions[shard]
|
||||
shard_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)
|
||||
if winning_root != Root():
|
||||
# Mark relevant pending attestations as creating a successful crosslink
|
||||
|
@ -920,9 +937,13 @@ def process_light_client_signatures(state: BeaconState, block_body: BeaconBlockB
|
|||
|
||||
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),
|
||||
get_domain(state, DOMAIN_LIGHT_CLIENT, compute_epoch_at_slot(slot)))
|
||||
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)
|
||||
```
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ def verify_shard_block_message(beacon_state: BeaconState,
|
|||
slot: Slot,
|
||||
shard: Shard) -> bool:
|
||||
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.proposer_index == get_shard_proposer_index(beacon_state, slot, shard)
|
||||
assert 0 < len(block.body) <= MAX_SHARD_BLOCK_SIZE
|
||||
|
@ -124,7 +123,6 @@ def is_valid_fraud_proof(beacon_state: BeaconState,
|
|||
subkey: BLSPubkey,
|
||||
beacon_parent_block: BeaconBlock) -> bool:
|
||||
# 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
|
||||
for j in range(custody_bits[offset_index]):
|
||||
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
|
||||
# `transition.shard_states[offset_index - 1]` to `transition.shard_states[offset_index]`.
|
||||
if offset_index == 0:
|
||||
shard = get_shard(beacon_state, attestation)
|
||||
shard_state = beacon_parent_block.shard_transitions[shard].shard_states[-1]
|
||||
else:
|
||||
shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here.
|
||||
|
|
|
@ -103,7 +103,7 @@ def upgrade_to_phase1(pre: phase0.BeaconState) -> BeaconState:
|
|||
ShardState(
|
||||
slot=pre.slot,
|
||||
gasprice=MIN_GASPRICE,
|
||||
data=Root(),
|
||||
transition_digest=Root(),
|
||||
latest_block_root=Root(),
|
||||
) 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
|
||||
next_light_committee=CompactCommittee(),
|
||||
# Custody game
|
||||
custody_challenge_index=0,
|
||||
exposed_derived_secrets=[] * EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS,
|
||||
# exposed_derived_secrets will fully default to zeroes
|
||||
)
|
||||
next_epoch = Epoch(epoch + 1)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from typing import List
|
||||
|
||||
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.keys import privkeys
|
||||
from eth2spec.utils import bls
|
||||
|
@ -43,7 +43,7 @@ def run_attestation_processing(spec, state, attestation, valid=True):
|
|||
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
|
||||
|
||||
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_root = state.current_justified_checkpoint.root
|
||||
|
||||
if spec.fork == PHASE1 and shard_transition is not None:
|
||||
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(
|
||||
attestation_data = spec.AttestationData(
|
||||
slot=slot,
|
||||
index=index,
|
||||
beacon_block_root=block_root,
|
||||
source=spec.Checkpoint(epoch=source_epoch, root=source_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):
|
||||
shard = spec.get_shard(state, attestation)
|
||||
offset_slots = spec.compute_offset_slots(spec.get_latest_slot_for_shard(state, shard), state.slot + 1)
|
||||
for offset_slot in offset_slots:
|
||||
offset_slots = spec.compute_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(
|
||||
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:
|
||||
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(
|
||||
state,
|
||||
|
@ -298,7 +314,21 @@ def next_epoch_with_attestations(spec,
|
|||
spec, post_state, slot_to_attest, index=index, signed=True, on_time=False)
|
||||
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_blocks.append(signed_block)
|
||||
|
||||
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
|
||||
|
|
|
@ -71,24 +71,31 @@ def build_empty_block(spec, state, slot=None):
|
|||
"""
|
||||
if slot is None:
|
||||
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.slot = slot
|
||||
empty_block.proposer_index = spec.get_beacon_proposer_index(state)
|
||||
empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index
|
||||
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)
|
||||
empty_block.parent_root = hash_tree_root(previous_block_header)
|
||||
empty_block.parent_root = parent_block_root
|
||||
apply_randao_reveal(spec, state, empty_block)
|
||||
return empty_block
|
||||
|
||||
|
||||
def build_empty_block_for_next_slot(spec, state):
|
||||
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
|
||||
|
|
|
@ -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.utils import 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,
|
||||
beacon_state,
|
||||
shard,
|
||||
slot,
|
||||
slot=None,
|
||||
body=None,
|
||||
signed=False):
|
||||
shard_state = beacon_state.shard_states[shard]
|
||||
if slot is None:
|
||||
slot = shard_state.slot
|
||||
slot = shard_state.slot + 1
|
||||
|
||||
if body is None:
|
||||
body = []
|
||||
body = b'\x56' * 128
|
||||
|
||||
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(
|
||||
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,
|
||||
proposer_index=proposer_index,
|
||||
body=body,
|
||||
|
@ -45,3 +49,40 @@ def build_shard_block(spec,
|
|||
sign_shard_block(spec, beacon_state, shard, signed_block, proposer_index=proposer_index)
|
||||
|
||||
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
|
||||
|
|
|
@ -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.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.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.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
|
||||
|
@ -420,12 +423,14 @@ def test_attestation(spec, 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
|
||||
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.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)
|
||||
|
||||
assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1
|
||||
|
|
|
@ -1,101 +1,78 @@
|
|||
from eth2spec.test.context import (
|
||||
PHASE0,
|
||||
with_all_phases_except,
|
||||
spec_state_test,
|
||||
always_bls,
|
||||
)
|
||||
from eth2spec.test.helpers.attestations import (
|
||||
get_valid_on_time_attestation,
|
||||
from eth2spec.test.helpers.crosslinks import run_crosslinks_processing
|
||||
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 (
|
||||
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
|
||||
from eth2spec.test.helpers.state import next_epoch, next_slot, transition_to
|
||||
|
||||
|
||||
@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
|
||||
@always_bls
|
||||
def test_basic_crosslinks(spec, state):
|
||||
next_epoch(spec, state)
|
||||
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
|
||||
run_basic_crosslink_tests(spec, state, target_len_offset_slot=1)
|
||||
|
||||
|
||||
@with_all_phases_except(['phase0'])
|
||||
@with_all_phases_except([PHASE0])
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_multiple_offset_slots(spec, state):
|
||||
next_epoch(spec, state)
|
||||
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
|
||||
run_basic_crosslink_tests(spec, state, target_len_offset_slot=3)
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue