text: import copy
  import random
  
  import itertools
  import pytest
  
  from hypothesis import (
      given,
      strategies as st,
  )
  
  from eth_utils import (
      ValidationError,
  )
  from eth_utils.toolz import (
      assoc,
      isdistinct,
  )
  
  from eth.constants import (
      ZERO_HASH32,
  )
  from eth2.beacon._utils.hash import (
      hash_eth2,
  )
  from eth2.beacon.constants import (
      GWEI_PER_ETH,
      FAR_FUTURE_SLOT,
  )
  from eth2.beacon.enums import (
      SignatureDomain,
  )
  from eth2.beacon.state_machines.forks.serenity.blocks import (
      SerenityBeaconBlock,
  )
  from eth2.beacon.types.attestation_data import (
      AttestationData,
  )
  from eth2.beacon.types.forks import Fork
  from eth2.beacon.types.slashable_vote_data import SlashableVoteData
  from eth2.beacon.types.states import BeaconState
  from eth2.beacon.types.validator_records import ValidatorRecord
  from eth2.beacon.helpers import (
      _get_block_root,
      generate_seed,
      get_active_validator_indices,
      get_attestation_participants,
      get_beacon_proposer_index,
      get_committee_count_per_slot,
      get_crosslink_committees_at_slot,
      get_current_epoch_committee_count_per_slot,
      get_domain,
      get_effective_balance,
      get_entry_exit_effect_slot,
      get_fork_version,
      get_previous_epoch_committee_count_per_slot,
      get_pubkey_for_indices,
      get_shuffling,
      generate_aggregate_pubkeys,
      verify_vote_count,
      verify_slashable_vote_data_signature,
      verify_slashable_vote_data,
      is_double_vote,
      is_surround_vote,
  )
  import eth2._utils.bls as bls
  
  from tests.eth2.beacon.helpers import (
      get_pseudo_chain,
  )
  
  
  @pytest.fixture()
  def sample_block(sample_beacon_block_params):
      return SerenityBeaconBlock(**sample_beacon_block_params)
  
  
  @pytest.fixture()
  def sample_state(sample_beacon_state_params):
      return BeaconState(**sample_beacon_state_params)
  
  
  def generate_mock_latest_block_roots(
          genesis_block,
          current_slot,
          epoch_length,
          latest_block_roots_length):
      assert current_slot < latest_block_roots_length
  
      chain_length = (current_slot // epoch_length + 1) * epoch_length
      blocks = get_pseudo_chain(chain_length, genesis_block)
      latest_block_roots = [
          block.hash
          for block in blocks[:current_slot]
      ] + [
          ZERO_HASH32
          for _ in range(latest_block_roots_length - current_slot)
      ]
      return blocks, latest_block_roots
  
  
  #
  # Get block rootes
  #
  @pytest.mark.parametrize(
      (
          'current_slot,target_slot,success'
      ),
      [
          (10, 0, True),
          (10, 9, True),
          (10, 10, False),
          (128, 0, True),
          (128, 127, True),
          (128, 128, False),
      ],
  )
  def test_get_block_root(current_slot,
                          target_slot,
                          success,
                          epoch_length,
                          latest_block_roots_length,
                          sample_block):
      blocks, latest_block_roots = generate_mock_latest_block_roots(
          sample_block,
          current_slot,
          epoch_length,
          latest_block_roots_length,
      )
  
      if success:
          block_root = _get_block_root(
              latest_block_roots,
              current_slot,
              target_slot,
              latest_block_roots_length,
          )
          assert block_root == blocks[target_slot].root
      else:
          with pytest.raises(ValidationError):
              _get_block_root(
                  latest_block_roots,
                  current_slot,
                  target_slot,
                  latest_block_roots_length,
              )
  
  
  #
  # Shuffling
  #
  @pytest.mark.parametrize(
      (
          'active_validator_count,'
          'epoch_length,'
          'target_committee_size,'
          'shard_count,'
          'expected_committee_count'
      ),
      [
          (1000, 20, 10, 50, 2),  # SHARD_COUNT // EPOCH_LENGTH
          (1000, 20, 10, 100, 5),  # active_validator_count // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE
          (20, 10, 3, 10, 1),  # 1
          (20, 10, 3, 5, 1),  # 1
          (40, 5, 2, 2, 1),  # 1
      ],
  )
  def test_get_committee_count_per_slot(active_validator_count,
                                        epoch_length,
                                        target_committee_size,
                                        shard_count,
                                        expected_committee_count):
      assert expected_committee_count == get_committee_count_per_slot(
          active_validator_count=active_validator_count,
          shard_count=shard_count,
          epoch_length=epoch_length,
          target_committee_size=target_committee_size,
      )
  
  
  @pytest.mark.parametrize(
      (
          'num_validators,'
          'epoch_length,'
          'target_committee_size,'
          'shard_count,'
          'slot'
      ),
      [
          (1000, 20, 10, 100, 0),
          (1000, 20, 10, 100, 5),
          (1000, 20, 10, 100, 30),
          (20, 10, 3, 10, 0),  # active_validators_size < epoch_length * target_committee_size
          (20, 10, 3, 10, 5),
          (20, 10, 3, 10, 30),
      ],
  )
  def test_get_shuffling_is_complete(activated_genesis_validators,
                                     epoch_length,
                                     target_committee_size,
                                     shard_count,
                                     slot):
      shuffling = get_shuffling(
          seed=b'\x35' * 32,
          validators=activated_genesis_validators,
          slot=slot,
          epoch_length=epoch_length,
          target_committee_size=target_committee_size,
          shard_count=shard_count,
      )
  
      assert len(shuffling) == epoch_length
      assert len(shuffling) > 0
      for committee in shuffling:
          assert len(committee) <= target_committee_size
          assert len(committee) > 0
      validator_indices = tuple(
          itertools.chain(
              [
                  validator_index
                  for committee in shuffling
                  for validator_index in committee
              ]
          )
      )
      assert isdistinct(validator_indices)
      activated_genesis_validator_indices = tuple(
          index
          for index in range(len(activated_genesis_validators))
      )
      assert sorted(validator_indices) == sorted(activated_genesis_validator_indices)
  
  
  @pytest.mark.parametrize(
      (
          'epoch_length,'
          'target_committee_size,'
          'shard_count,'
          'len_active_validators,'
          'previous_epoch_calculation_slot, current_epoch_calculation_slot,'
          'get_epoch_committee_count_per_slot,'
          'delayed_activation_slot'
      ),
      [
          (
              1, 1, 2, 2,
              5, 10,
              get_previous_epoch_committee_count_per_slot,
              5 + 1,
          ),
          (
              1, 1, 2, 10,
              5, 10,
              get_previous_epoch_committee_count_per_slot,
              5 + 1,
          ),
          (
              1, 1, 2, 2,
              5, 10,
              get_current_epoch_committee_count_per_slot,
              10 + 1,
          ),
          (
              1, 1, 2, 10,
              5, 10,
              get_current_epoch_committee_count_per_slot,
              10 + 1,
          ),
      ],
  )
  def test_get_epoch_committee_count_per_slot(monkeypatch,
                                              ten_validators_state,
                                              epoch_length,
                                              target_committee_size,
                                              shard_count,
                                              len_active_validators,
                                              previous_epoch_calculation_slot,
                                              current_epoch_calculation_slot,
                                              get_epoch_committee_count_per_slot,
                                              delayed_activation_slot):
      from eth2.beacon import helpers
  
      def mock_get_committee_count_per_slot(active_validator_count,
                                            shard_count,
                                            epoch_length,
                                            target_committee_size):
          return active_validator_count // epoch_length // shard_count
  
      monkeypatch.setattr(
          helpers,
          'get_committee_count_per_slot',
          mock_get_committee_count_per_slot
      )
  
      state = ten_validators_state.copy(
          slot=0,
          previous_epoch_calculation_slot=previous_epoch_calculation_slot,
          current_epoch_calculation_slot=current_epoch_calculation_slot,
      )
      for index in range(len(state.validator_registry)):
          if index < len_active_validators:
              validator = state.validator_registry[index].copy(
                  activation_slot=0,
              )
              state = state.update_validator_registry(
                  index,
                  validator,
              )
          else:
              validator = state.validator_registry[index].copy(
                  activation_slot=delayed_activation_slot,
              )
              state = state.update_validator_registry(
                  index,
                  validator,
              )
  
      result_committee_count = get_epoch_committee_count_per_slot(
          state=state,
          shard_count=shard_count,
          epoch_length=epoch_length,
          target_committee_size=target_committee_size,
      )
      expected_committee_count = len_active_validators // epoch_length // shard_count
  
      assert result_committee_count == expected_committee_count
  
  
  @pytest.mark.parametrize(
      (
          'state_epoch_slot,'
          'slot,'
          'epoch_length,'
          'target_committee_size,'
          'shard_count,'
      ),
      [
          (10, 5, 10, 10, 10),  # slot < state_epoch_slot
          (10, 10, 10, 10, 10),  # slot >= state_epoch_slot
          (10, 11, 10, 10, 10),  # slot >= state_epoch_slot
      ],
  )
  def test_get_crosslink_committees_at_slot(
          ten_validators_state,
          state_epoch_slot,
          slot,
          epoch_length,
          target_committee_size,
          shard_count):
  
      state = ten_validators_state.copy(
          slot=state_epoch_slot,
      )
  
      crosslink_committees_at_slot = get_crosslink_committees_at_slot(
          state=state,
          slot=slot,
          epoch_length=epoch_length,
          target_committee_size=target_committee_size,
          shard_count=shard_count,
      )
      assert len(crosslink_committees_at_slot) > 0
      for crosslink_committee in crosslink_committees_at_slot:
          committee, shard = crosslink_committee
          assert len(committee) > 0
          assert shard < shard_count
  
  
  #
  # Get proposer postition
  #
  @pytest.mark.parametrize(
      (
          'num_validators,'
          'epoch_length,'
          'committee,'
          'slot,'
          'success,'
      ),
      [
          (
              100,
              64,
              (10, 11, 12),
              0,
              True,
          ),
          (
              100,
              64,
              (),
              0,
              False,
          ),
      ]
  )
  def test_get_beacon_proposer_index(
          monkeypatch,
          num_validators,
          epoch_length,
          committee,
          slot,
          success,
          sample_state,
          target_committee_size,
          shard_count):
  
      from eth2.beacon import helpers
  
      def mock_get_crosslink_committees_at_slot(state,
                                                slot,
                                                epoch_length,
                                                target_committee_size,
                                                shard_count):
          return (
              (committee, 1,),
          )
  
      monkeypatch.setattr(
          helpers,
          'get_crosslink_committees_at_slot',
          mock_get_crosslink_committees_at_slot
      )
      if success:
          proposer_index = get_beacon_proposer_index(
              sample_state,
              slot,
              epoch_length,
              target_committee_size,
              shard_count,
          )
          assert proposer_index == committee[slot % len(committee)]
      else:
          with pytest.raises(ValidationError):
              get_beacon_proposer_index(
                  sample_state,
                  slot,
                  epoch_length,
                  target_committee_size,
                  shard_count,
              )
  
  
  def test_get_active_validator_indices(sample_validator_record_params):
      current_slot = 1
      # 3 validators are ACTIVE
      validators = [
          ValidatorRecord(
              **sample_validator_record_params,
          ).copy(
              activation_slot=0,
              exit_slot=FAR_FUTURE_SLOT,
          )
          for i in range(3)
      ]
      active_validator_indices = get_active_validator_indices(validators, current_slot)
      assert len(active_validator_indices) == 3
  
      validators[0] = validators[0].copy(
          activation_slot=current_slot + 1,  # activation_slot > current_slot
      )
      active_validator_indices = get_active_validator_indices(validators, current_slot)
      assert len(active_validator_indices) == 2
  
  
  @pytest.mark.parametrize(
      (
          'num_validators,'
          'epoch_length,'
          'committee,'
          'aggregation_bitfield,'
          'expected'
      ),
      [
          (
              100,
              64,
              (10, 11, 12),
              b'\00',
              (),
          ),
          (
              100,
              64,
              (10, 11, 12),
              b'\x80',
              (10,),
          ),
          (
              100,
              64,
              (10, 11, 12),
              b'\xc0',
              (10, 11),
          ),
          (
              100,
              64,
              (10, 11, 12),
              b'\x00\x00',
              ValueError(),
          ),
      ]
  )
  def test_get_attestation_participants(
          monkeypatch,
          num_validators,
          epoch_length,
          committee,
          aggregation_bitfield,
          expected,
          sample_state,
          target_committee_size,
          shard_count,
          sample_attestation_data_params):
      shard = 1
  
      from eth2.beacon import helpers
  
      def mock_get_crosslink_committees_at_slot(state,
                                                slot,
                                                epoch_length,
                                                target_committee_size,
                                                shard_count):
          return (
              (committee, shard,),
          )
  
      monkeypatch.setattr(
          helpers,
          'get_crosslink_committees_at_slot',
          mock_get_crosslink_committees_at_slot
      )
  
      attestation_data = AttestationData(**sample_attestation_data_params).copy(
          slot=0,
          shard=shard,
      )
      if isinstance(expected, Exception):
          with pytest.raises(ValidationError):
              get_attestation_participants(
                  state=sample_state,
                  attestation_data=attestation_data,
                  aggregation_bitfield=aggregation_bitfield,
                  epoch_length=epoch_length,
                  target_committee_size=target_committee_size,
                  shard_count=shard_count,
              )
      else:
          result = get_attestation_participants(
              state=sample_state,
              attestation_data=attestation_data,
              aggregation_bitfield=aggregation_bitfield,
              epoch_length=epoch_length,
              target_committee_size=target_committee_size,
              shard_count=shard_count,
          )
  
          assert result == expected
  
  
  @pytest.mark.parametrize(
      (
          'balance,'
          'max_deposit,'
          'expected'
      ),
      [
          (
              1 * GWEI_PER_ETH,
              32,
              1 * GWEI_PER_ETH,
          ),
          (
              32 * GWEI_PER_ETH,
              32,
              32 * GWEI_PER_ETH,
          ),
          (
              33 * GWEI_PER_ETH,
              32,
              32 * GWEI_PER_ETH,
          )
      ]
  )
  def test_get_effective_balance(balance, max_deposit, expected, sample_validator_record_params):
      balances = (balance,)
      result = get_effective_balance(balances, 0, max_deposit)
      assert result == expected
  
  
  @pytest.mark.parametrize(
      (
          'previous_version,'
          'current_version,'
          'slot,'
          'current_slot,'
          'expected'
      ),
      [
          (0, 0, 0, 0, 0),
          (0, 0, 0, 1, 0),
          (0, 1, 20, 10, 0),
          (0, 1, 20, 20, 1),
          (0, 1, 10, 20, 1),
      ]
  )
  def test_get_fork_version(previous_version,
                            current_version,
                            slot,
                            current_slot,
                            expected):
      fork = Fork(
          previous_version=previous_version,
          current_version=current_version,
          slot=slot,
      )
      assert expected == get_fork_version(
          fork,
          current_slot,
      )
  
  
  @pytest.mark.parametrize(
      (
          'previous_version,'
          'current_version,'
          'slot,'
          'current_slot,'
          'domain_type,'
          'expected'
      ),
      [
          (1, 2, 20, 10, 10, 1 * 2 ** 32 + 10),
          (1, 2, 20, 20, 11, 2 * 2 ** 32 + 11),
          (1, 2, 10, 20, 12, 2 * 2 ** 32 + 12),
      ]
  )
  def test_get_domain(previous_version,
                      current_version,
                      slot,
                      current_slot,
                      domain_type,
                      expected):
      fork = Fork(
          previous_version=previous_version,
          current_version=current_version,
          slot=slot,
      )
      assert expected == get_domain(
          fork=fork,
          slot=current_slot,
          domain_type=domain_type,
      )
  
  
  def _generate_some_indices(data, max_value_for_list):
      """
      Hypothesis helper that generates a list of some integers [0, `max_value_for_list`].
      The usage is to randomly sample some elements from a sequence of some element.
      """
      return data.draw(
          st.lists(
              st.integers(
                  min_value=0,
                  max_value=max_value_for_list,
              ),
          )
      )
  
  
  @given(st.data())
  def test_get_pubkey_for_indices(activated_genesis_validators, data):
      max_value_for_list = len(activated_genesis_validators) - 1
      indices = _generate_some_indices(data, max_value_for_list)
      pubkeys = get_pubkey_for_indices(activated_genesis_validators, indices)
  
      assert len(indices) == len(pubkeys)
  
      for index, pubkey in enumerate(pubkeys):
          validator_index = indices[index]
          assert activated_genesis_validators[validator_index].pubkey == pubkey
  
  
  def _list_and_index(data, max_size=None, elements=st.integers()):
      """
      Hypothesis helper function cribbed from their docs on @composite
      """
      xs = data.draw(st.lists(elements, max_size=max_size))
      i = data.draw(st.integers(min_value=0, max_value=max(len(xs) - 1, 0)))
      return (xs, i)
  
  
  @given(st.data())
  def test_generate_aggregate_pubkeys(activated_genesis_validators,
                                      sample_slashable_vote_data_params,
                                      data):
      max_value_for_list = len(activated_genesis_validators) - 1
      (indices, some_index) = _list_and_index(
          data,
          elements=st.integers(
              min_value=0,
              max_value=max_value_for_list,
          )
      )
      custody_bit_0_indices = indices[:some_index]
      custody_bit_1_indices = indices[some_index:]
  
      key = "custody_bit_0_indices"
      sample_slashable_vote_data_params[key] = custody_bit_0_indices
      key = "custody_bit_1_indices"
      sample_slashable_vote_data_params[key] = custody_bit_1_indices
  
      votes = SlashableVoteData(**sample_slashable_vote_data_params)
  
      keys = generate_aggregate_pubkeys(activated_genesis_validators, votes)
      assert len(keys) == 2
  
      (poc_0_key, poc_1_key) = keys
  
      poc_0_keys = get_pubkey_for_indices(activated_genesis_validators, custody_bit_0_indices)
      poc_1_keys = get_pubkey_for_indices(activated_genesis_validators, custody_bit_1_indices)
  
      assert bls.aggregate_pubkeys(poc_0_keys) == poc_0_key
      assert bls.aggregate_pubkeys(poc_1_keys) == poc_1_key
  
  
  @given(st.data())
  def test_verify_vote_count(max_casper_votes, sample_slashable_vote_data_params, data):
      (indices, some_index) = _list_and_index(data, max_size=max_casper_votes)
      custody_bit_0_indices = indices[:some_index]
      custody_bit_1_indices = indices[some_index:]
  
      key = "custody_bit_0_indices"
      sample_slashable_vote_data_params[key] = custody_bit_0_indices
      key = "custody_bit_1_indices"
      sample_slashable_vote_data_params[key] = custody_bit_1_indices
  
      votes = SlashableVoteData(**sample_slashable_vote_data_params)
  
      assert verify_vote_count(votes, max_casper_votes)
  
  
  def _get_indices_and_signatures(num_validators, message, privkeys, fork, slot):
      num_indices = 5
      assert num_validators >= num_indices
      indices = random.sample(range(num_validators), num_indices)
      privkeys = [privkeys[i] for i in indices]
      domain_type = SignatureDomain.DOMAIN_ATTESTATION
      domain = get_domain(
          fork=fork,
          slot=slot,
          domain_type=domain_type,
      )
      signatures = tuple(
          map(lambda key: bls.sign(message, key, domain), privkeys)
      )
      return (indices, signatures)
  
  
  def _correct_slashable_vote_data_params(num_validators, params, messages, privkeys, fork):
      valid_params = copy.deepcopy(params)
  
      key = "custody_bit_0_indices"
      (poc_0_indices, poc_0_signatures) = _get_indices_and_signatures(
          num_validators,
          messages[0],
          privkeys,
          fork,
          params["data"].slot,
      )
      valid_params[key] = poc_0_indices
  
      key = "custody_bit_1_indices"
      # NOTE: does not guarantee non-empty intersection
      (poc_1_indices, poc_1_signatures) = _get_indices_and_signatures(
          num_validators,
          messages[1],
          privkeys,
          fork,
          params["data"].slot,
      )
      valid_params[key] = poc_1_indices
  
      signatures = poc_0_signatures + poc_1_signatures
      aggregate_signature = bls.aggregate_signatures(signatures)
  
      valid_params["aggregate_signature"] = aggregate_signature
  
      return valid_params
  
  
  def _corrupt_signature(params, fork):
      message = bytes.fromhex("deadbeefcafe")
      privkey = 42
      domain_type = SignatureDomain.DOMAIN_ATTESTATION
      domain = get_domain(
          fork=fork,
          slot=params["data"].slot,
          domain_type=domain_type,
      )
      corrupt_signature = bls.sign(message, privkey, domain)
  
      return assoc(params, "aggregate_signature", corrupt_signature)
  
  
  def _corrupt_vote_count(params):
      key = "custody_bit_0_indices"
      for i in itertools.count():
          if i not in params[key]:
              new_vote_count = params[key] + [i]
              return assoc(
                  params,
                  key,
                  new_vote_count,
              )
      else:
          raise Exception("Unreachable code path")
  
  
  def _create_slashable_vote_data_messages(params):
      # TODO update when we move to `ssz` tree hash
      votes = SlashableVoteData(**params)
      return votes.messages
  
  
  @pytest.mark.parametrize(
      (
          'num_validators',
      ),
      [
          (40,),
      ]
  )
  def test_verify_slashable_vote_data_signature(num_validators,
                                                privkeys,
                                                sample_beacon_state_params,
                                                activated_genesis_validators,
                                                genesis_balances,
                                                sample_slashable_vote_data_params,
                                                sample_fork_params):
      state = BeaconState(**sample_beacon_state_params).copy(
          validator_registry=activated_genesis_validators,
          validator_balances=genesis_balances,
          fork=Fork(**sample_fork_params),
      )
  
      # NOTE: we can do this before "correcting" the params as they
      # touch disjoint subsets of the provided params
      messages = _create_slashable_vote_data_messages(sample_slashable_vote_data_params)
  
      valid_params = _correct_slashable_vote_data_params(
          num_validators,
          sample_slashable_vote_data_params,
          messages,
          privkeys,
          state.fork,
      )
      valid_votes = SlashableVoteData(**valid_params)
      assert verify_slashable_vote_data_signature(state, valid_votes)
  
      invalid_params = _corrupt_signature(valid_params, state.fork)
      invalid_votes = SlashableVoteData(**invalid_params)
      assert not verify_slashable_vote_data_signature(state, invalid_votes)
  
  
  def _run_verify_slashable_vote(params, state, max_casper_votes, should_succeed):
      votes = SlashableVoteData(**params)
      result = verify_slashable_vote_data(state, votes, max_casper_votes)
      if should_succeed:
          assert result
      else:
          assert not result
  
  
  @pytest.mark.parametrize(
      (
          'num_validators',
      ),
      [
          (40,),
      ]
  )
  @pytest.mark.parametrize(
      (
          'param_mapper',
          'should_succeed',
          'needs_fork',
      ),
      [
          (lambda params: params, True, False),
          (_corrupt_vote_count, False, False),
          (_corrupt_signature, False, True),
          (lambda params, fork: _corrupt_vote_count(
              _corrupt_signature(params, fork)
          ), False, True),
      ],
  )
  def test_verify_slashable_vote_data(num_validators,
                                      param_mapper,
                                      should_succeed,
                                      needs_fork,
                                      privkeys,
                                      sample_beacon_state_params,
                                      activated_genesis_validators,
                                      genesis_balances,
                                      sample_slashable_vote_data_params,
                                      sample_fork_params,
                                      max_casper_votes):
      state = BeaconState(**sample_beacon_state_params).copy(
          validator_registry=activated_genesis_validators,
          validator_balances=genesis_balances,
          fork=Fork(**sample_fork_params),
      )
  
      # NOTE: we can do this before "correcting" the params as they
      # touch disjoint subsets of the provided params
      messages = _create_slashable_vote_data_messages(sample_slashable_vote_data_params)
  
      params = _correct_slashable_vote_data_params(
          num_validators,
          sample_slashable_vote_data_params,
          messages,
          privkeys,
          state.fork,
      )
      if needs_fork:
          params = param_mapper(params, state.fork)
      else:
          params = param_mapper(params)
      _run_verify_slashable_vote(params, state, max_casper_votes, should_succeed)
  
  
  @pytest.mark.parametrize(
      (
          'num_validators',
      ),
      [
          (40,),
      ]
  )
  def test_verify_slashable_vote_data_after_fork(num_validators,
                                                 privkeys,
                                                 sample_beacon_state_params,
                                                 activated_genesis_validators,
                                                 genesis_balances,
                                                 sample_slashable_vote_data_params,
                                                 sample_fork_params,
                                                 max_casper_votes):
      # Test that slashable data is still valid after fork
      # Slashable data slot = 10, fork slot = 15, current slot = 20
      past_fork_params = {
          'previous_version': 0,
          'current_version': 1,
          'slot': 15,
      }
  
      state = BeaconState(**sample_beacon_state_params).copy(
          validator_registry=activated_genesis_validators,
          validator_balances=genesis_balances,
          fork=Fork(**past_fork_params),
          slot=20,
      )
  
      messages = _create_slashable_vote_data_messages(sample_slashable_vote_data_params)
  
      valid_params = _correct_slashable_vote_data_params(
          num_validators,
          sample_slashable_vote_data_params,
          messages,
          privkeys,
          state.fork,
      )
      _run_verify_slashable_vote(valid_params, state, max_casper_votes, True)
  
  
  def test_is_double_vote(sample_attestation_data_params):
      attestation_data_1_params = {
          **sample_attestation_data_params,
          'slot': 12345,
      }
      attestation_data_1 = AttestationData(**attestation_data_1_params)
  
      attestation_data_2_params = {
          **sample_attestation_data_params,
          'slot': 12345,
      }
      attestation_data_2 = AttestationData(**attestation_data_2_params)
  
      assert is_double_vote(attestation_data_1, attestation_data_2)
  
      attestation_data_3_params = {
          **sample_attestation_data_params,
          'slot': 54321,
      }
      attestation_data_3 = AttestationData(**attestation_data_3_params)
  
      assert not is_double_vote(attestation_data_1, attestation_data_3)
  
  
  @pytest.mark.parametrize(
      (
          'attestation_1_slot,'
          'attestation_1_justified_slot,'
          'attestation_2_slot,'
          'attestation_2_justified_slot,'
          'expected'
      ),
      [
          (0, 0, 0, 0, False),
          (4, 3, 3, 2, False),  # not (attestation_1_justified_slot < attestation_2_justified_slot
          (4, 0, 3, 1, False),  # not (attestation_2_justified_slot + 1 == attestation_2_slot)
          (4, 0, 4, 3, False),  # not (attestation_2_slot < attestation_1_slot)
          (4, 0, 3, 2, True),
      ],
  )
  def test_is_surround_vote(sample_attestation_data_params,
                            attestation_1_slot,
                            attestation_1_justified_slot,
                            attestation_2_slot,
                            attestation_2_justified_slot,
                            expected):
      attestation_data_1_params = {
          **sample_attestation_data_params,
          'slot': attestation_1_slot,
          'justified_slot': attestation_1_justified_slot,
      }
      attestation_data_1 = AttestationData(**attestation_data_1_params)
  
      attestation_data_2_params = {
          **sample_attestation_data_params,
          'slot': attestation_2_slot,
          'justified_slot': attestation_2_justified_slot,
      }
      attestation_data_2 = AttestationData(**attestation_data_2_params)
  
      assert is_surround_vote(attestation_data_1, attestation_data_2) == expected
  
  
  @pytest.mark.parametrize(
      (
          'slot,'
          'epoch_length,'
          'entry_exit_delay,'
          'expected_entry_exit_effect_slot'
      ),
      # result = (slot - slot % EPOCH_LENGTH) + EPOCH_LENGTH + ENTRY_EXIT_DELAY
      [
          (64, 64, 128, (64 - 64 % 64) + 64 + 128),
          (128, 64, 128, (128 - 128 % 64) + 64 + 128),
      ],
  )
  def test_get_entry_exit_effect_slot(slot,
                                      epoch_length,
                                      entry_exit_delay,
                                      expected_entry_exit_effect_slot):
      # TODO: update to epoch version
      entry_exit_effect_slot = get_entry_exit_effect_slot(
          slot,
          epoch_length,
          entry_exit_delay,
      )
      assert entry_exit_effect_slot == expected_entry_exit_effect_slot
  
  
  def test_generate_seed(monkeypatch,
                         genesis_state,
                         epoch_length,
                         seed_lookahead,
                         latest_index_roots_length,
                         latest_randao_mixes_length):
      from eth2.beacon import helpers
  
      def mock_get_randao_mix(state,
                              slot,
                              latest_randao_mixes_length):
          return hash_eth2(
              state.root +
              abs(slot).to_bytes(32, byteorder='big') +
              latest_randao_mixes_length.to_bytes(32, byteorder='big')
          )
  
      def mock_get_active_index_root(state,
                                     slot,
                                     epoch_length,
                                     latest_index_roots_length):
          return hash_eth2(
              state.root +
              abs(slot).to_bytes(32, byteorder='big') +
              epoch_length.to_bytes(32, byteorder='big') +
              latest_index_roots_length.to_bytes(32, byteorder='big')
          )
  
      monkeypatch.setattr(
          helpers,
          'get_randao_mix',
          mock_get_randao_mix
      )
      monkeypatch.setattr(
          helpers,
          'get_active_index_root',
          mock_get_active_index_root
      )
  
      state = genesis_state
      slot = 10
  
      seed = generate_seed(
          state=state,
          slot=slot,
          epoch_length=epoch_length,
          seed_lookahead=seed_lookahead,
          latest_index_roots_length=latest_index_roots_length,
          latest_randao_mixes_length=latest_randao_mixes_length,
      )
      assert seed == hash_eth2(
          mock_get_randao_mix(
              state,
              slot - seed_lookahead,
              latest_randao_mixes_length=latest_randao_mixes_length,
          ) + mock_get_active_index_root(
              state,
              slot,
              epoch_length=epoch_length,
              latest_index_roots_length=latest_index_roots_length,
          )
      )
  