def test_pending_shard_parent_block(spec, state): # Block N beacon_state = state.copy() transition_to_valid_shard_slot(spec, beacon_state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block_1 = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) _, _, _, _ = run_shard_blocks(spec, shard_state, signed_shard_block_1, beacon_state) # Block N+1 next_slot(spec, beacon_state) signed_shard_block_2 = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, shard_parent_state=shard_state, signed=True) assert signed_shard_block_2.message.shard_parent_root == shard_state.latest_block_root assert signed_shard_block_2.message.slot == signed_shard_block_1.message.slot + 1 yield from run_shard_blocks(spec, shard_state, signed_shard_block_2, beacon_state)
def test_with_shard_transition_with_custody_challenge_and_response(spec, state): transition_to_valid_shard_slot(spec, state) # build shard block shard = 0 committee_index = get_committee_index_of_shard(spec, state, state.slot, shard) body = get_sample_shard_block_body(spec) shard_block = build_shard_block(spec, state, shard, body=body, slot=state.slot, signed=True) shard_block_dict: Dict[spec.Shard, Sequence[spec.SignedShardBlock]] = {shard: [shard_block]} shard_transitions = get_shard_transitions(spec, state, shard_block_dict) attestation = get_valid_on_time_attestation( spec, state, index=committee_index, shard_transition=shard_transitions[shard], signed=True, ) block = build_empty_block(spec, state, slot=state.slot + 1) block.body.attestations = [attestation] block.body.shard_transitions = shard_transitions # CustodyChunkChallenge operation challenge = get_valid_chunk_challenge(spec, state, attestation, shard_transitions[shard]) block.body.chunk_challenges = [challenge] # CustodyChunkResponse operation chunk_challenge_index = state.custody_chunk_challenge_index custody_response = get_valid_custody_chunk_response( spec, state, challenge, chunk_challenge_index, block_length_or_custody_data=body) block.body.chunk_challenge_responses = [custody_response] yield from run_beacon_block(spec, state, block)
def test_invalid_slot(spec, state): if not is_full_crosslink(spec, state): # skip return beacon_state = transition_to_valid_shard_slot(spec, state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) signed_shard_block.message.slot = beacon_state.slot + 1 proposer_index = spec.get_shard_proposer_index( beacon_state, signed_shard_block.message.slot, shard) sign_shard_block(spec, beacon_state, shard, signed_shard_block, proposer_index=proposer_index) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state, valid=False)
def test_out_of_bound_offset(spec, state): # TODO: Handle this edge case properly if not is_full_crosslink(spec, state): # skip return beacon_state = transition_to_valid_shard_slot(spec, state) shard = 0 slot = ( beacon_state.shard_states[shard].slot + spec.SHARD_BLOCK_OFFSETS[spec.MAX_SHARD_BLOCKS_PER_ATTESTATION - 1] + 1 # out-of-bound ) transition_to(spec, beacon_state, slot) shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state, valid=False)
def test_process_beacon_block_with_normal_shard_transition(spec, state): state = transition_to_valid_shard_slot(spec, state) target_len_offset_slot = 1 committee_index = spec.CommitteeIndex(0) shard = spec.compute_shard_from_committee_index(state, committee_index, state.slot) assert state.shard_states[shard].slot == state.slot - 1 pre_gasprice = state.shard_states[shard].gasprice # Create SignedShardBlock at slot `shard_state.slot + 1` body = b'\x56' * spec.MAX_SHARD_BLOCK_SIZE shard_block = build_shard_block(spec, state, shard, body=body, signed=True) shard_blocks: Dict[spec.Shard, Sequence[spec.SignedShardBlock]] = { shard: [shard_block] } yield from run_beacon_block_with_shard_blocks(spec, state, shard_blocks, target_len_offset_slot, committee_index) shard_state = state.shard_states[shard] if target_len_offset_slot == 1 and len(shard_blocks) > 0: assert shard_state.gasprice > pre_gasprice
def test_invalid_proposer_index(spec, state): beacon_state = state.copy() transition_to_valid_shard_slot(spec, beacon_state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) active_validator_indices = spec.get_active_validator_indices( beacon_state, spec.get_current_epoch(beacon_state)) proposer_index = ((spec.get_shard_proposer_index( beacon_state, signed_shard_block.message.slot, shard) + 1) % len(active_validator_indices)) signed_shard_block.message.proposer_index = proposer_index sign_shard_block(spec, beacon_state, shard, signed_shard_block, proposer_index=proposer_index) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state, valid=False)
def create_simple_fork(spec, state, store, shard): # Beacon block beacon_block = create_beacon_block_with_shard_transition( spec, state, store, shard, []) apply_beacon_block_to_store(spec, state, store, beacon_block) beacon_head_root = spec.get_head(store) assert beacon_head_root == beacon_block.hash_tree_root() beacon_parent_state = store.block_states[beacon_head_root] shard_store = store.shard_stores[shard] shard_parent_state = shard_store.block_states[spec.get_shard_head( store, shard)] # Shard block A body = b'\x56' * 4 forking_block_child = build_shard_block( spec, beacon_parent_state, shard, shard_parent_state=shard_parent_state, slot=beacon_parent_state.slot, body=body, signed=True) run_on_shard_block(spec, store, forking_block_child) # Shard block B body = b'\x78' * 4 # different body shard_block_b = build_shard_block(spec, beacon_parent_state, shard, shard_parent_state=shard_parent_state, slot=beacon_parent_state.slot, body=body, signed=True) run_on_shard_block(spec, store, shard_block_b) # Set forking_block current_head = spec.get_shard_head(store, shard) if current_head == forking_block_child.message.hash_tree_root(): head_block = forking_block_child forking_block = shard_block_b else: assert current_head == shard_block_b.message.hash_tree_root() head_block = shard_block_b forking_block = forking_block_child return head_block, forking_block
def test_no_winning_root(spec, state): if not is_full_crosslink(spec, state): # Skip this test return state, shard, target_shard_slot = get_initial_env(spec, state, target_len_offset_slot=1) init_slot = state.slot # Create SignedShardBlock at init_slot shard_block = build_shard_block(spec, state, shard, slot=init_slot, body=get_sample_shard_block_body( spec, is_max=True), signed=True) # Transition state to target shard slot transition_to(spec, state, target_shard_slot) # Create a shard_transitions that would be included at beacon block `target_shard_slot + 1` shard_transitions = get_shard_transitions(spec, state, {shard: [shard_block]}) shard_transition = shard_transitions[shard] committee_index = get_committee_index_of_shard(spec, state, state.slot, shard) attestation = get_valid_attestation( spec, state, index=committee_index, shard_transition=shard_transition, # Decrease attested participants to 1/3 committee filter_participant_set=lambda committee: set( list(committee)[:len(committee) // 3]), signed=True, on_time=True, ) next_slot(spec, state) _, _, _ = run_attestation_processing(spec, state, attestation) _, winning_roots = spec.get_shard_winning_roots(state, [attestation]) assert len(winning_roots) == 0 # No winning root, shard_transitions[shard] is empty shard_transitions = [spec.ShardTransition()] * spec.MAX_SHARDS pre_shard_states = state.shard_states.copy() yield from run_shard_transitions_processing(spec, state, shard_transitions, [attestation]) for pending_attestation in state.current_epoch_attestations: assert bool(pending_attestation.crosslink_success) is False assert state.shard_states == pre_shard_states
def test_custody_slashing(spec, state): # NOTE: this test is only for full crosslink (minimal config), not for mainnet if not is_full_crosslink(spec, state): # skip return state = transition_to_valid_shard_slot(spec, state) # Build shard block shard = 0 committee_index = get_committee_index_of_shard(spec, state, state.slot, shard) # Create slashable shard block body validator_index = spec.get_beacon_committee(state, state.slot, committee_index)[0] custody_secret = get_custody_secret(spec, state, validator_index) slashable_body = get_custody_slashable_test_vector(spec, custody_secret, length=100, slashable=True) shard_block = build_shard_block(spec, state, shard, body=slashable_body, slot=state.slot, signed=True) shard_block_dict: Dict[spec.Shard, Sequence[spec.SignedShardBlock]] = { shard: [shard_block] } shard_transitions = get_shard_transitions(spec, state, shard_block_dict) attestation = get_valid_on_time_attestation( spec, state, index=committee_index, shard_transition=shard_transitions[shard], signed=True, ) block = build_empty_block(spec, state, slot=state.slot + 1) block.body.attestations = [attestation] block.body.shard_transitions = shard_transitions _, _, _ = run_beacon_block(spec, state, block) transition_to( spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1)) block = build_empty_block(spec, state, slot=state.slot + 1) custody_slashing = get_valid_custody_slashing(spec, state, attestation, shard_transitions[shard], custody_secret, slashable_body) block.body.custody_slashings = [custody_slashing] yield from run_beacon_block(spec, state, block)
def test_custody_slashing(spec, state): transition_to_valid_shard_slot(spec, state) # Build shard block shard = 0 committee_index = get_committee_index_of_shard(spec, state, state.slot, shard) # Create slashable shard block body validator_index = spec.get_beacon_committee(state, state.slot, committee_index)[0] custody_secret = spec.get_custody_secret( state, validator_index, privkeys[validator_index], spec.get_current_epoch(state), ) slashable_body = get_custody_slashable_test_vector(spec, custody_secret, length=100, slashable=True) shard_block = build_shard_block(spec, state, shard, body=slashable_body, slot=state.slot, signed=True) shard_block_dict: Dict[spec.Shard, Sequence[spec.SignedShardBlock]] = { shard: [shard_block] } shard_transitions = get_shard_transitions(spec, state, shard_block_dict) attestation = get_valid_on_time_attestation( spec, state, index=committee_index, shard_transition=shard_transitions[shard], signed=True, ) block = build_empty_block(spec, state, slot=state.slot + 1) block.body.attestations = [attestation] block.body.shard_transitions = shard_transitions _, _, _ = run_beacon_block(spec, state, block) transition_to( spec, state, state.slot + spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_CUSTODY_PERIOD - 1)) block = build_empty_block(spec, state, slot=state.slot + 1) custody_slashing = get_valid_custody_slashing(spec, state, attestation, shard_transitions[shard], custody_secret, slashable_body) block.body.custody_slashings = [custody_slashing] yield from run_beacon_block(spec, state, block)
def test_wrong_shard_transition_root(spec, state): if not is_full_crosslink(spec, state): # Skip this test return state, shard, target_shard_slot = get_initial_env(spec, state, target_len_offset_slot=1) init_slot = state.slot # Create SignedShardBlock at init_slot shard_block = build_shard_block(spec, state, shard, slot=init_slot, body=get_sample_shard_block_body( spec, is_max=True), signed=True) # Transition state to target shard slot transition_to(spec, state, target_shard_slot) # Create a shard_transitions that would be included at beacon block `target_shard_slot + 1` shard_transitions = get_shard_transitions(spec, state, {shard: [shard_block]}) shard_transition = shard_transitions[shard] wrong_shard_transition = shard_transition.copy() wrong_shard_transition.shard_states[ shard].gasprice = shard_transition.shard_states[shard].gasprice + 1 committee_index = get_committee_index_of_shard(spec, state, state.slot, shard) attestation = get_valid_attestation( spec, state, index=committee_index, shard_transition=wrong_shard_transition, signed=True, on_time=True, ) attestations = [attestation] next_slot(spec, state) run_attestation_processing(spec, state, attestation) # Check if winning root != shard_transition.hash_tree_root() _, winning_roots = spec.get_shard_winning_roots(state, attestations) assert len(winning_roots) == 1 shard_transition = shard_transitions[shard] assert winning_roots[0] != shard_transition.hash_tree_root() yield from run_shard_transitions_processing(spec, state, shard_transitions, attestations, valid=False)
def create_and_apply_shard_block(spec, store, shard, beacon_parent_state, shard_blocks_buffer): body = b'\x56' * 4 shard_head_root = spec.get_shard_head(store, shard) shard_store = store.shard_stores[shard] shard_parent_state = shard_store.block_states[shard_head_root] assert shard_parent_state.slot != beacon_parent_state.slot shard_block = build_shard_block( spec, beacon_parent_state, shard, shard_parent_state=shard_parent_state, slot=beacon_parent_state.slot, body=body, signed=True ) shard_blocks_buffer.append(shard_block) run_on_shard_block(spec, store, shard_block) assert spec.get_shard_head(store, shard) == shard_block.message.hash_tree_root()
def run_successful_crosslink_tests(spec, state, target_len_offset_slot): state, shard, target_shard_slot = get_initial_env(spec, state, target_len_offset_slot) init_slot = state.slot # Create SignedShardBlock at init_slot shard_block = build_shard_block(spec, state, shard, slot=init_slot, body=get_sample_shard_block_body( spec, is_max=True), signed=True) # Transition state to target shard slot transition_to(spec, state, target_shard_slot) # Create a shard_transitions that would be included at beacon block `target_shard_slot + 1` shard_block_dict = {shard: [shard_block]} attestations, shard_transitions = get_attestations_and_shard_transitions( spec, state, shard_block_dict) next_slot(spec, state) for attestation in attestations: _, _, _ = run_attestation_processing(spec, state, attestation) _, winning_roots = spec.get_shard_winning_roots(state, attestations) assert len(winning_roots) == 1 shard_transition = shard_transitions[shard] assert winning_roots[0] == shard_transition.hash_tree_root() pre_gasprice = state.shard_states[shard].gasprice pre_shard_states = state.shard_states.copy() yield from run_shard_transitions_processing(spec, state, shard_transitions, attestations) for index, shard_state in enumerate(state.shard_states): if index == shard: assert shard_state != pre_shard_states[index] assert shard_state == shard_transition.shard_states[ len(shard_transition.shard_states) - 1] assert shard_state.latest_block_root == shard_block.message.hash_tree_root( ) if target_len_offset_slot == 1: assert shard_state.gasprice > pre_gasprice else: assert shard_state == pre_shard_states[index] for pending_attestation in state.current_epoch_attestations: assert bool(pending_attestation.crosslink_success) is True
def test_valid_shard_block(spec, state): beacon_state = state.copy() transition_to_valid_shard_slot(spec, beacon_state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, state, shard, slot=beacon_state.slot, signed=True) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state)
def run_beacon_block_with_shard_blocks(spec, state, target_len_offset_slot, committee_index, shard, valid=True): transition_to(spec, state, state.slot + target_len_offset_slot) body = get_sample_shard_block_body(spec, is_max=True) shard_block = build_shard_block(spec, state, shard, body=body, slot=state.slot, signed=True) shard_block_dict: Dict[spec.Shard, Sequence[spec.SignedShardBlock]] = {shard: [shard_block]} shard_transitions = get_shard_transitions(spec, state, shard_block_dict) attestations = [ get_valid_on_time_attestation( spec, state, index=committee_index, shard_transition=shard_transitions[shard], signed=True, ) for shard in shard_block_dict.keys() ] beacon_block = build_empty_block(spec, state, slot=state.slot + 1) beacon_block.body.attestations = attestations beacon_block.body.shard_transitions = shard_transitions pre_gasprice = state.shard_states[shard].gasprice pre_shard_states = state.shard_states.copy() yield 'pre', state.copy() if not valid: state_transition_and_sign_block(spec, state, beacon_block, expect_fail=True) yield 'block', beacon_block yield 'post', None return signed_beacon_block = state_transition_and_sign_block(spec, state, beacon_block) yield 'block', signed_beacon_block yield 'post', state for shard in range(spec.get_active_shard_count(state)): post_shard_state = state.shard_states[shard] if shard in shard_block_dict: # Shard state has been changed to state_transition result assert post_shard_state == shard_transitions[shard].shard_states[ len(shard_transitions[shard].shard_states) - 1 ] assert post_shard_state.slot == state.slot - 1 if len((shard_block_dict[shard])) == 0: # `latest_block_root` is the same assert post_shard_state.latest_block_root == pre_shard_states[shard].latest_block_root if target_len_offset_slot == 1 and len(shard_block_dict[shard]) > 0: assert post_shard_state.gasprice > pre_gasprice
def run_basic_crosslink_tests(spec, state, target_len_offset_slot, valid=True): state = transition_to_valid_shard_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 body = b'\x56' * spec.MAX_SHARD_BLOCK_SIZE shard_block = build_shard_block(spec, state, shard, body=body, signed=True) shard_blocks = [shard_block] # Create a shard_transitions that would be included at beacon block `state.slot + target_len_offset_slot` shard_transitions = build_shard_transitions_till_slot( spec, state, shard_blocks={shard: shard_blocks}, on_time_slot=state.slot + target_len_offset_slot, ) shard_transition = shard_transitions[shard] # Create an attestation that would be included at beacon block `state.slot + target_len_offset_slot` attestation = build_attestation_with_shard_transition( spec, state, index=committee_index, on_time_slot=state.slot + target_len_offset_slot, shard_transition=shard_transition, ) pre_gasprice = state.shard_states[shard].gasprice transition_to(spec, state, state.slot + target_len_offset_slot) pre_shard_state = state.shard_states[shard] yield from run_crosslinks_processing(spec, state, shard_transitions, [attestation], valid=valid) if valid: # 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
def test_valid_shard_block(spec, state): if not is_full_crosslink(spec, state): # skip return beacon_state = transition_to_valid_shard_slot(spec, state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state)
def test_max_offset(spec, state): beacon_state = state.copy() transition_to_valid_shard_slot(spec, beacon_state) shard = 0 slot = beacon_state.shard_states[shard].slot + spec.SHARD_BLOCK_OFFSETS[ spec.MAX_SHARD_BLOCKS_PER_ATTESTATION - 1] transition_to(spec, beacon_state, slot) shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state)
def test_invalid_beacon_parent_root(spec, state): beacon_state = state.copy() transition_to_valid_shard_slot(spec, beacon_state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) signed_shard_block.message.beacon_parent_root = b'\x12' * 32 sign_shard_block(spec, beacon_state, shard, signed_shard_block) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state, valid=False)
def test_max_offset(spec, state): if not is_full_crosslink(spec, state): # skip return beacon_state = transition_to_valid_shard_slot(spec, state) shard = 0 slot = beacon_state.shard_states[shard].slot + spec.SHARD_BLOCK_OFFSETS[ spec.MAX_SHARD_BLOCKS_PER_ATTESTATION - 1] transition_to(spec, beacon_state, slot) shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state)
def test_invalid_shard_parent_root(spec, state): if not is_full_crosslink(spec, state): # skip return beacon_state = transition_to_valid_shard_slot(spec, state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) signed_shard_block.message.shard_parent_root = b'\x12' * 32 sign_shard_block(spec, beacon_state, shard, signed_shard_block) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state, valid=False)
def test_invalid_offset(spec, state): beacon_state = state.copy() transition_to_valid_shard_slot(spec, beacon_state) # 4 is not in `SHARD_BLOCK_OFFSETS` shard = 0 slot = beacon_state.shard_states[shard].slot + 4 assert slot not in spec.SHARD_BLOCK_OFFSETS transition_to(spec, beacon_state, slot) shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state, valid=False)
def test_invalid_slot(spec, state): beacon_state = state.copy() transition_to_valid_shard_slot(spec, beacon_state) shard = 0 shard_state = beacon_state.shard_states[shard] signed_shard_block = build_shard_block(spec, beacon_state, shard, slot=beacon_state.slot, signed=True) signed_shard_block.message.slot = beacon_state.slot + 1 proposer_index = spec.get_shard_proposer_index( beacon_state, signed_shard_block.message.slot, shard) sign_shard_block(spec, beacon_state, shard, signed_shard_block, proposer_index=proposer_index) yield from run_shard_blocks(spec, shard_state, signed_shard_block, beacon_state, valid=False)