def test_invalid_proposer_index_sig_from_proposer_index(spec, state): yield 'pre', state block = build_empty_block_for_next_slot(spec, state) # Set invalid proposer index but correct signature wrt proposer_index active_indices = spec.get_active_validator_indices(state, spec.get_current_epoch(state)) active_indices = [i for i in active_indices if i != block.proposer_index] block.proposer_index = active_indices[0] # invalid proposer index invalid_signed_block = sign_block(spec, state, block, block.proposer_index) expect_assertion_error(lambda: spec.state_transition(state, invalid_signed_block)) yield 'blocks', [invalid_signed_block] yield 'post', None
def test_invalid_signature_bad_domain(spec, state): committee_indices = compute_committee_indices(spec, state) block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, # full committee signs block_root=block.parent_root, domain_type=spec.DOMAIN_BEACON_ATTESTER, # Incorrect domain ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_on_attestation_future_epoch(spec, state): store = spec.get_forkchoice_store(state) time = store.time + 3 * spec.SECONDS_PER_SLOT spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) # store block in store spec.on_block(store, signed_block) # move state forward but not store next_epoch(spec, state) attestation = get_valid_attestation(spec, state, slot=state.slot, signed=True) run_on_attestation(spec, state, store, attestation, False)
def test_on_attestation_future_block(spec, state): store = spec.get_forkchoice_store(state) time = store.time + spec.SECONDS_PER_SLOT * 5 spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) spec.on_block(store, signed_block) # attestation for slot immediately prior to the block being attested to attestation = get_valid_attestation(spec, state, slot=block.slot - 1, signed=False) attestation.data.beacon_block_root = block.hash_tree_root() sign_attestation(spec, state, attestation) run_on_attestation(spec, state, store, attestation, False)
def test_empty_epoch_transition(spec, state): pre_slot = state.slot yield 'pre', state block = build_empty_block_for_next_slot(spec, state) block.slot += spec.SLOTS_PER_EPOCH sign_block(spec, state, block) state_transition_and_sign_block(spec, state, block) yield 'blocks', [block] yield 'post', state assert state.slot == block.slot for slot in range(pre_slot, state.slot): assert spec.get_block_root_at_slot(state, slot) == block.parent_root
def test_on_block_bad_parent_root(spec, state): # Initialization store = spec.get_genesis_store(state) time = 100 spec.on_tick(store, time) # Fail receiving block of `GENESIS_SLOT + 1` slot block = build_empty_block_for_next_slot(spec, state) transition_unsigned_block(spec, state, block) block.state_root = state.hash_tree_root() block.parent_root = b'\x45' * 32 signed_block = sign_block(spec, state, block) run_on_block(spec, store, signed_block, False)
def test_on_attestation_future_epoch(spec, state): store = spec.get_genesis_store(state) time = 3 * spec.SECONDS_PER_SLOT spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) state_transition_and_sign_block(spec, state, block) # store block in store spec.on_block(store, block) # move state forward but not store state.slot = block.slot + spec.SLOTS_PER_EPOCH attestation = get_valid_attestation(spec, state, slot=state.slot) run_on_attestation(spec, state, store, attestation, False)
def test_invalid_block_sig(spec, state): yield 'pre', state block = build_empty_block_for_next_slot(spec, state) invalid_signed_block = spec.SignedBeaconBlock( message=block, signature=bls_sign(message_hash=hash_tree_root(block), privkey=123456, domain=spec.get_domain( state, spec.DOMAIN_BEACON_PROPOSER, spec.compute_epoch_at_slot(block.slot)))) expect_assertion_error( lambda: spec.state_transition(state, invalid_signed_block)) yield 'blocks', [invalid_signed_block] yield 'post', None
def build_attestation_data(spec, state, slot, shard): assert state.slot >= slot if slot == state.slot: block_root = build_empty_block_for_next_slot(spec, state).parent_root else: block_root = spec.get_block_root_at_slot(state, slot) current_epoch_start_slot = spec.get_epoch_start_slot( spec.get_current_epoch(state)) if slot < current_epoch_start_slot: epoch_boundary_root = spec.get_block_root( state, spec.get_previous_epoch(state)) elif slot == current_epoch_start_slot: epoch_boundary_root = block_root else: epoch_boundary_root = spec.get_block_root( state, spec.get_current_epoch(state)) if slot < current_epoch_start_slot: justified_epoch = state.previous_justified_epoch justified_block_root = state.previous_justified_root else: justified_epoch = state.current_justified_epoch justified_block_root = state.current_justified_root if spec.slot_to_epoch(slot) == spec.get_current_epoch(state): parent_crosslink = state.current_crosslinks[shard] else: parent_crosslink = state.previous_crosslinks[shard] return spec.AttestationData( beacon_block_root=block_root, source_epoch=justified_epoch, source_root=justified_block_root, target_epoch=spec.slot_to_epoch(slot), target_root=epoch_boundary_root, crosslink=spec.Crosslink( shard=shard, start_epoch=parent_crosslink.end_epoch, end_epoch=min( spec.slot_to_epoch(slot), parent_crosslink.end_epoch + spec.MAX_EPOCHS_PER_CROSSLINK), data_root=spec.ZERO_HASH, parent_root=hash_tree_root(parent_crosslink), ), )
def test_on_block_finalized_skip_slots_not_in_skip_chain(spec, state): """ Test case was originally from https://github.com/ethereum/consensus-specs/pull/1579 And then rewrote largely. """ test_steps = [] # Initialization store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state) yield 'anchor_state', state yield 'anchor_block', anchor_block current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time on_tick_and_append_step(spec, store, current_time, test_steps) assert store.time == current_time # Fill epoch 0 and the first slot of epoch 1 state, store, _ = yield from apply_next_slots_with_attestations( spec, state, store, spec.SLOTS_PER_EPOCH, True, False, test_steps) # Skip the rest slots of epoch 1 and the first slot of epoch 2 next_slots(spec, state, spec.SLOTS_PER_EPOCH) # Fill epoch 3 and 4 for _ in range(2): state, store, _ = yield from apply_next_epoch_with_attestations( spec, state, store, True, True, test_steps=test_steps) # Now we get finalized epoch 2, where `compute_start_slot_at_epoch(2)` is a skipped slot assert state.finalized_checkpoint.epoch == store.finalized_checkpoint.epoch == 2 assert store.finalized_checkpoint.root == spec.get_block_root( state, 1) == spec.get_block_root(state, 2) assert state.current_justified_checkpoint.epoch == store.justified_checkpoint.epoch == 3 assert store.justified_checkpoint == state.current_justified_checkpoint # Now build a block after the block of the finalized **root** # Includes finalized block in chain, but does not include finalized skipped slots another_state = store.block_states[store.finalized_checkpoint.root].copy() assert another_state.slot == spec.compute_start_slot_at_epoch( store.finalized_checkpoint.epoch - 1) block = build_empty_block_for_next_slot(spec, another_state) signed_block = state_transition_and_sign_block(spec, another_state, block) yield from tick_and_add_block(spec, store, signed_block, test_steps, valid=False) yield 'steps', test_steps
def test_on_attestation_previous_epoch(spec, state): store = spec.get_genesis_store(state) spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) block = build_empty_block_for_next_slot(spec, state) state_transition_and_sign_block(spec, state, block) # store block in store spec.on_block(store, block) attestation = get_valid_attestation(spec, state, slot=block.slot) assert attestation.data.target.epoch == spec.GENESIS_EPOCH assert spec.compute_epoch_at_slot( spec.get_current_slot(store)) == spec.GENESIS_EPOCH + 1 run_on_attestation(spec, state, store, attestation)
def test_invalid_signature_missing_participant(spec, state): committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) rng = random.Random(2020) random_participant = rng.choice(committee_indices) block = build_empty_block_for_next_slot(spec, state) # Exclude one participant whose signature was included. block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[index != random_participant for index in committee_indices], sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, # full committee signs ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_historical_batch(spec, state): state.slot += spec.SLOTS_PER_HISTORICAL_ROOT - ( state.slot % spec.SLOTS_PER_HISTORICAL_ROOT) - 1 pre_historical_roots_len = len(state.historical_roots) yield 'pre', state block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state assert state.slot == block.slot assert spec.get_current_epoch(state) % (spec.SLOTS_PER_HISTORICAL_ROOT // spec.SLOTS_PER_EPOCH) == 0 assert len(state.historical_roots) == pre_historical_roots_len + 1
def test_skipped_slots(spec, state): pre_slot = state.slot yield 'pre', state block = build_empty_block_for_next_slot(spec, state) block.slot += 3 sign_block(spec, state, block) state_transition_and_sign_block(spec, state, block) yield 'blocks', [block], List[spec.BeaconBlock] yield 'post', state assert state.slot == block.slot assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.ZERO_HASH for slot in range(pre_slot, state.slot): assert spec.get_block_root_at_slot(state, slot) == block.parent_root
def test_on_block_future_block(spec, state): test_steps = [] # Initialization store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state) yield 'anchor_state', state yield 'anchor_block', anchor_block current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time on_tick_and_append_step(spec, store, current_time, test_steps) assert store.time == current_time # Do NOT tick time to `GENESIS_SLOT + 1` slot # Fail receiving block of `GENESIS_SLOT + 1` slot block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) yield from add_block(spec, store, signed_block, test_steps, valid=False) yield 'steps', test_steps
def test_empty_block_transition_large_validator_set(spec, state): pre_slot = state.slot pre_eth1_votes = len(state.eth1_data_votes) pre_mix = spec.get_randao_mix(state, spec.get_current_epoch(state)) yield 'pre', state block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state assert len(state.eth1_data_votes) == pre_eth1_votes + 1 assert spec.get_block_root_at_slot(state, pre_slot) == signed_block.message.parent_root assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != pre_mix
def test_empty_block_transition(spec, state): pre_slot = state.slot pre_eth1_votes = len(state.eth1_data_votes) yield 'pre', state block = build_empty_block_for_next_slot(spec, state, signed=True) state_transition_and_sign_block(spec, state, block) yield 'blocks', [block] yield 'post', state assert len(state.eth1_data_votes) == pre_eth1_votes + 1 assert spec.get_block_root_at_slot(state, pre_slot) == block.parent_root assert spec.get_randao_mix( state, spec.get_current_epoch(state)) != spec.Bytes32()
def test_double_validator_exit_same_block(spec, state): validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # Same index tries to exit twice, but should only be able to do so once. signed_exits = prepare_signed_exits(spec, state, [validator_index, validator_index]) yield 'pre', state # Add to state via block transition initiate_exit_block = build_empty_block_for_next_slot(spec, state) initiate_exit_block.body.voluntary_exits = signed_exits signed_initiate_exit_block = state_transition_and_sign_block(spec, state, initiate_exit_block, expect_fail=True) yield 'blocks', [signed_initiate_exit_block] yield 'post', None
def _build_block_for_next_slot_with_sync_participation(spec, state, committee_indices, committee_bits): block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=committee_bits, sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, [ index for index, bit in zip(committee_indices, committee_bits) if bit ], block_root=block.parent_root, )) return block
def test_on_attestation_target_not_in_store(spec, state): store = spec.get_genesis_store(state) time = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH spec.on_tick(store, time) # move to immediately before next epoch to make block new target transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH - 1) target_block = build_empty_block_for_next_slot(spec, state) state_transition_and_sign_block(spec, state, target_block) # do not add target block to store attestation = get_valid_attestation(spec, state, slot=target_block.slot) assert attestation.data.target.root == target_block.signing_root() run_on_attestation(spec, state, store, attestation, False)
def test_multiple_attester_slashings_partial_overlap(spec, state): if spec.MAX_ATTESTER_SLASHINGS < 2: return dump_skipping_message( "Skip test if config cannot handle multiple AttesterSlashings per block" ) # copy for later balance lookups. pre_state = state.copy() full_indices = spec.get_active_validator_indices( state, spec.get_current_epoch(state))[:8] one_third_length = len(full_indices) // 3 attester_slashing_1 = get_valid_attester_slashing_by_indices( spec, state, full_indices[:one_third_length * 2], signed_1=True, signed_2=True, ) attester_slashing_2 = get_valid_attester_slashing_by_indices( spec, state, full_indices[one_third_length:], signed_1=True, signed_2=True, ) attester_slashings = [attester_slashing_1, attester_slashing_2] assert not any(state.validators[i].slashed for i in full_indices) yield 'pre', state # # Add to state via block transition # block = build_empty_block_for_next_slot(spec, state) block.body.attester_slashings = attester_slashings signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state check_attester_slashing_effect(spec, pre_state, state, full_indices)
def test_on_attestation_target_block_not_in_store(spec, state): store = get_genesis_forkchoice_store(spec, state) time = store.time + spec.config.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) spec.on_tick(store, time) # move to immediately before next epoch to make block new target next_epoch = spec.get_current_epoch(state) + 1 transition_to(spec, state, spec.compute_start_slot_at_epoch(next_epoch) - 1) target_block = build_empty_block_for_next_slot(spec, state) state_transition_and_sign_block(spec, state, target_block) # do not add target block to store attestation = get_valid_attestation(spec, state, slot=target_block.slot, signed=True) assert attestation.data.target.root == target_block.hash_tree_root() run_on_attestation(spec, state, store, attestation, False)
def test_basic(spec, state): # Initialization store = get_genesis_forkchoice_store(spec, state) time = 100 spec.on_tick(store, time) assert store.time == time # On receiving a block of `GENESIS_SLOT + 1` slot block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) run_on_block(spec, store, signed_block) # On receiving a block of next epoch store.time = time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH block = build_empty_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH) signed_block = state_transition_and_sign_block(spec, state, block) run_on_block(spec, store, signed_block)
def test_on_attestation_invalid_attestation(spec, state): store = get_genesis_forkchoice_store(spec, state) time = store.time + 3 * spec.SECONDS_PER_SLOT spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) spec.on_block(store, signed_block) attestation = get_valid_attestation(spec, state, slot=block.slot, signed=True) # make invalid by using an invalid committee index attestation.data.index = spec.MAX_COMMITTEES_PER_SLOT * spec.SLOTS_PER_EPOCH run_on_attestation(spec, state, store, attestation, False)
def test_expected_deposit_in_block(spec, state): # Make the state expect a deposit, then don't provide it. state.eth1_data.deposit_count += 1 yield 'pre', state block = build_empty_block_for_next_slot(spec, state) sign_block(spec, state, block) bad = False try: state_transition_and_sign_block(spec, state, block) bad = True except AssertionError: pass if bad: raise AssertionError("expected deposit was not enforced") yield 'blocks', [block] yield 'post', None
def test_proposer_self_slashing(spec, state): yield 'pre', state block = build_empty_block_for_next_slot(spec, state) assert not state.validators[block.proposer_index].slashed proposer_slashing = get_valid_proposer_slashing( spec, state, slashed_index=block.proposer_index, signed_1=True, signed_2=True) block.body.proposer_slashings.append(proposer_slashing) # The header is processed *before* the block body: # the proposer was not slashed before the body, thus the block is valid. signed_block = state_transition_and_sign_block(spec, state, block) # The proposer slashed themselves. assert state.validators[block.proposer_index].slashed yield 'blocks', [signed_block] yield 'post', state
def test_on_attestation_past_epoch(spec, state): store = get_genesis_forkchoice_store(spec, state) # move time forward 2 epochs time = store.time + 2 * spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH spec.on_tick(store, time) # create and store block from 3 epochs ago block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) spec.on_block(store, signed_block) # create attestation for past block attestation = get_valid_attestation(spec, state, slot=state.slot, signed=True) assert attestation.data.target.epoch == spec.GENESIS_EPOCH assert spec.compute_epoch_at_slot(spec.get_current_slot(store)) == spec.GENESIS_EPOCH + 2 run_on_attestation(spec, state, store, attestation, False)
def test_invalid_signature_extra_participant(spec, state): committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) rng = random.Random(3030) random_participant = rng.choice(committee_indices) block = build_empty_block_for_next_slot(spec, state) # Exclude one signature even though the block claims the entire committee participated. block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, [index for index in committee_indices if index != random_participant], ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def compute_sync_committee_signature(spec, state, slot, privkey, block_root=None, domain_type=None): if not domain_type: domain_type = spec.DOMAIN_SYNC_COMMITTEE domain = spec.get_domain(state, domain_type, spec.compute_epoch_at_slot(slot)) if block_root is None: if slot == state.slot: block_root = build_empty_block_for_next_slot(spec, state).parent_root else: block_root = spec.get_block_root_at_slot(state, slot) signing_root = spec.compute_signing_root(block_root, domain) return bls.Sign(privkey, signing_root)
def test_double_same_proposer_slashings_same_block(spec, state): proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True) slashed_index = proposer_slashing.signed_header_1.message.proposer_index assert not state.validators[slashed_index].slashed yield 'pre', state block = build_empty_block_for_next_slot(spec, state) block.body.proposer_slashings = [proposer_slashing, proposer_slashing] signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True) yield 'blocks', [signed_block] yield 'post', None