Update shard fork choice rule to be able to handle mainnet config

This commit is contained in:
Hsiao-Wei Wang 2020-06-04 20:32:31 +08:00
parent f8597d2965
commit ab42eee4c0
No known key found for this signature in database
GPG Key ID: 95B070122902DEA4
1 changed files with 62 additions and 35 deletions

View File

@ -1,6 +1,6 @@
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
from eth2spec.test.context import spec_state_test, with_all_phases_except, PHASE0
from eth2spec.test.context import PHASE0, spec_state_test, with_all_phases_except, never_bls
from eth2spec.test.helpers.shard_block import (
build_attestation_with_shard_transition,
build_shard_block,
@ -8,7 +8,7 @@ from eth2spec.test.helpers.shard_block import (
get_committee_index_of_shard,
)
from eth2spec.test.helpers.fork_choice import add_block_to_store, get_anchor_root
from eth2spec.test.helpers.state import next_slot, state_transition_and_sign_block
from eth2spec.test.helpers.state import state_transition_and_sign_block
from eth2spec.test.helpers.block import build_empty_block
@ -25,35 +25,51 @@ def run_on_shard_block(spec, store, shard_store, signed_block, valid=True):
assert shard_store.blocks[hash_tree_root(signed_block.message)] == signed_block.message
def run_apply_shard_and_beacon(spec, state, store, shard_store, shard_blocks_buffer):
def apply_shard_block(spec, store, shard_store, beacon_head_state, shard_blocks_buffer):
shard = shard_store.shard
committee_index = get_committee_index_of_shard(spec, state, state.slot, shard)
has_shard_committee = committee_index is not None
body = b'\x56' * 4
shard_head_root = spec.get_shard_head(store, shard_store)
shard_parent_state = shard_store.block_states[shard_head_root]
assert shard_parent_state.slot != beacon_head_state.slot
shard_block = build_shard_block(
spec, beacon_head_state, shard,
shard_parent_state=shard_parent_state, slot=beacon_head_state.slot, body=body, signed=True
)
shard_blocks_buffer.append(shard_block)
run_on_shard_block(spec, store, shard_store, shard_block)
assert spec.get_shard_head(store, shard_store) == shard_block.message.hash_tree_root()
def check_pending_shard_blocks(spec, store, shard_store, shard_blocks_buffer):
pending_shard_blocks = [
spec.SignedShardBlock(message=b)
for b in spec.get_pendings_shard_blocks(store, shard_store)
]
assert pending_shard_blocks == shard_blocks_buffer
def is_in_offset_sets(spec, beacon_head_state, shard):
offset_slots = spec.compute_offset_slots(
beacon_head_state.shard_states[shard].slot, beacon_head_state.slot + 1
)
return beacon_head_state.slot in offset_slots
def apply_shard_and_beacon(spec, state, store, shard_store, shard_blocks_buffer):
store.time = store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
# Create SignedShardBlock
# Check offsets
temp_state = state.copy()
next_slot(spec, temp_state)
offset_slots = spec.get_offset_slots(temp_state, shard)
if state.slot in offset_slots:
# Build block
body = b'\x56' * 4
shard_head_root = spec.get_shard_head(store, shard_store)
shard_parent_state = shard_store.block_states[shard_head_root]
assert shard_parent_state.slot != state.slot
shard_block = build_shard_block(
spec, state, shard,
shard_parent_state=shard_parent_state, slot=state.slot, body=body, signed=True
)
shard_blocks_buffer.append(shard_block)
run_on_shard_block(spec, store, shard_store, shard_block)
assert spec.get_shard_head(store, shard_store) == shard_block.message.hash_tree_root()
shard = shard_store.shard
committee_index = get_committee_index_of_shard(spec, state, state.slot, shard)
has_shard_committee = committee_index is not None # has committee of `shard` at this slot
# On beacon blocks at `state.slot + 1`
beacon_block = build_empty_block(spec, state, slot=state.slot + 1)
# Attester creates `attestation`
# If next slot has committee of `shard`, add `shard_transtion` to the proposing beacon block
if has_shard_committee and len(shard_blocks_buffer) > 0:
# Sanity check `get_pendings_shard_blocks` function
check_pending_shard_blocks(spec, store, shard_store, shard_blocks_buffer)
# Use temporary next state to get ShardTransition of shard block
shard_transitions = build_shard_transitions_till_slot(
spec,
@ -62,7 +78,6 @@ def run_apply_shard_and_beacon(spec, state, store, shard_store, shard_blocks_buf
on_time_slot=state.slot + 1,
)
shard_transition = shard_transitions[shard]
attestation = build_attestation_with_shard_transition(
spec,
state,
@ -75,35 +90,47 @@ def run_apply_shard_and_beacon(spec, state, store, shard_store, shard_blocks_buf
beacon_block.body.attestations = [attestation]
beacon_block.body.shard_transitions = shard_transitions
signed_beacon_block = state_transition_and_sign_block(spec, state, beacon_block)
# Clear buffer
shard_blocks_buffer.clear()
signed_beacon_block = state_transition_and_sign_block(spec, state, beacon_block)
add_block_to_store(spec, store, signed_beacon_block)
assert spec.get_head(store) == beacon_block.hash_tree_root()
if has_shard_committee:
shard_blocks_buffer = [] # clear buffer
# On shard block at updated `state.slot`
if is_in_offset_sets(spec, state, shard):
# The created shard block would be appended to `shard_blocks_buffer`
apply_shard_block(spec, store, shard_store, state, shard_blocks_buffer)
return has_shard_committee, shard_blocks_buffer
return has_shard_committee
@with_all_phases_except([PHASE0])
@spec_state_test
@never_bls # Set to never_bls for testing `check_pending_shard_blocks`
def test_basic(spec, state):
spec.PHASE_1_GENESIS_SLOT = 0 # FIXME: remove mocking
spec.PHASE_1_GENESIS_SLOT = 0 # NOTE: mock genesis slot here
state = spec.upgrade_to_phase1(state)
shard = spec.Shard(1)
# Initialization
store = spec.get_forkchoice_store(state)
anchor_root = get_anchor_root(spec, state)
assert spec.get_head(store) == anchor_root
shard = spec.Shard(1)
shard_store = spec.get_forkchoice_shard_store(state, shard)
shard_block_count = 2
shard_head_root = spec.get_shard_head(store, shard_store)
assert shard_head_root == state.shard_states[shard].latest_block_root
assert shard_store.block_states[shard_head_root].slot == 1
assert shard_store.block_states[shard_head_root] == state.shard_states[shard]
# For mainnet config, it's possible that only one committee of `shard` per epoch.
# we set this counter to test more rounds.
shard_committee_counter = 2
shard_blocks_buffer = []
while shard_block_count > 0:
has_shard_committee, shard_blocks_buffer = run_apply_shard_and_beacon(
while shard_committee_counter > 0:
has_shard_committee = apply_shard_and_beacon(
spec, state, store, shard_store, shard_blocks_buffer
)
if has_shard_committee:
shard_block_count -= 1
shard_committee_counter -= 1