예제 #1
0
def validate_proposer_slashing_epoch(proposer_slashing: ProposerSlashing,
                                     slots_per_epoch: int) -> None:
    epoch_1 = compute_epoch_of_slot(proposer_slashing.header_1.slot,
                                    slots_per_epoch)
    epoch_2 = compute_epoch_of_slot(proposer_slashing.header_2.slot,
                                    slots_per_epoch)

    if epoch_1 != epoch_2:
        raise ValidationError(
            f"Epoch of proposer_slashing.proposal_1 ({epoch_1}) !="
            f" epoch of proposer_slashing.proposal_2 ({epoch_2})")
예제 #2
0
async def test_validator_attest(event_loop, event_bus, monkeypatch):
    alice_indices = [i for i in range(8)]
    alice = await get_validator(event_loop=event_loop, event_bus=event_bus, indices=alice_indices)
    head = alice.chain.get_canonical_head()
    state_machine = alice.chain.get_state_machine()
    state = alice.chain.get_head_state()

    epoch = compute_epoch_of_slot(state.slot, state_machine.config.SLOTS_PER_EPOCH)
    assignment = alice._get_this_epoch_assignment(alice_indices[0], epoch)

    attestations = await alice.attest(assignment.slot)
    assert len(attestations) == 1
    attestation = attestations[0]
    assert get_attestation_data_slot(
        state,
        attestation.data,
        state_machine.config,
    ) == assignment.slot
    assert attestation.data.beacon_block_root == head.signing_root
    assert attestation.data.crosslink.shard == assignment.shard

    # Advance the state and validate the attestation
    config = state_machine.config
    future_state = state_machine.state_transition.apply_state_transition(
        state,
        future_slot=assignment.slot + config.MIN_ATTESTATION_INCLUSION_DELAY,
    )
    validate_attestation(
        future_state,
        attestation,
        config,
    )
예제 #3
0
def create_mock_slashable_attestation(
    state: BeaconState,
    config: Eth2Config,
    keymap: Dict[BLSPubkey, int],
    attestation_slot: Slot,
) -> IndexedAttestation:
    """
    Create an `IndexedAttestation` that is signed by one attester.
    """
    attester_index = ValidatorIndex(0)
    committee = (attester_index, )
    shard = Shard(0)

    # Use genesis block root as `beacon_block_root`, only for tests.
    beacon_block_root = get_block_root_at_slot(
        state, attestation_slot, config.SLOTS_PER_HISTORICAL_ROOT)

    # Get `target_root`
    target_root = _get_target_root(state, config, beacon_block_root)
    # Get `source_root`
    source_root = get_block_root_at_slot(
        state,
        compute_start_slot_of_epoch(state.current_justified_checkpoint.epoch,
                                    config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_HISTORICAL_ROOT,
    )
    previous_crosslink = state.current_crosslinks[shard]

    attestation_data = AttestationData(
        beacon_block_root=beacon_block_root,
        source=Checkpoint(epoch=state.current_justified_checkpoint.epoch,
                          root=source_root),
        target=Checkpoint(
            epoch=compute_epoch_of_slot(attestation_slot,
                                        config.SLOTS_PER_EPOCH),
            root=target_root,
        ),
        crosslink=previous_crosslink,
    )

    message_hash = _get_mock_message(attestation_data)
    attesting_indices = _get_mock_attesting_indices(committee,
                                                    num_voted_attesters=1)

    signature = sign_transaction(
        message_hash=message_hash,
        privkey=keymap[state.validators[attesting_indices[0]].pubkey],
        state=state,
        slot=attestation_slot,
        signature_domain=SignatureDomain.DOMAIN_ATTESTATION,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )
    validator_indices = tuple(committee[i] for i in attesting_indices)

    return IndexedAttestation(
        custody_bit_0_indices=validator_indices,
        custody_bit_1_indices=tuple(),
        data=attestation_data,
        signature=signature,
    )
예제 #4
0
def _find_latest_attestation_targets(
        state: BeaconState, store: Store,
        config: Eth2Config) -> Iterable[AttestationTarget]:
    epoch = compute_epoch_of_slot(state.slot, config.SLOTS_PER_EPOCH)
    active_validators = get_active_validator_indices(state.validators, epoch)
    return filter(
        second, map(_find_latest_attestation_target(store), active_validators))
예제 #5
0
파일: chain.py 프로젝트: skylenet/trinity
 def _get_highest_justified_epoch(self, db: DatabaseAPI) -> Epoch:
     try:
         justified_head_root = self._get_justified_head_root(db)
         slot = self.get_slot_by_root(justified_head_root)
         return compute_epoch_of_slot(slot, self.genesis_config.SLOTS_PER_EPOCH)
     except JustifiedHeadNotFound:
         return self.genesis_config.GENESIS_EPOCH
예제 #6
0
def create_mock_signed_attestations_at_slot(
        state: BeaconState,
        config: Eth2Config,
        state_machine: BaseBeaconStateMachine,
        attestation_slot: Slot,
        beacon_block_root: Hash32,
        keymap: Dict[BLSPubkey, int],
        voted_attesters_ratio: float = 1.0) -> Iterable[Attestation]:
    """
    Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``.
    """
    crosslink_committees_at_slot = get_crosslink_committees_at_slot(
        state,
        attestation_slot,
        config,
    )

    # Get `target_root`
    target_root = _get_target_root(state, config, beacon_block_root)
    target_epoch = compute_epoch_of_slot(
        state.slot,
        config.SLOTS_PER_EPOCH,
    )

    for crosslink_committee in crosslink_committees_at_slot:
        committee, shard = crosslink_committee

        parent_crosslink = state.current_crosslinks[shard]

        attestation_data = AttestationData(
            beacon_block_root=beacon_block_root,
            source=Checkpoint(
                epoch=state.current_justified_checkpoint.epoch,
                root=state.current_justified_checkpoint.root,
            ),
            target=Checkpoint(
                root=target_root,
                epoch=target_epoch,
            ),
            crosslink=Crosslink(
                shard=shard,
                parent_root=parent_crosslink.hash_tree_root,
                start_epoch=parent_crosslink.end_epoch,
                end_epoch=min(
                    target_epoch, parent_crosslink.end_epoch +
                    config.MAX_EPOCHS_PER_CROSSLINK),
            ))

        num_voted_attesters = int(len(committee) * voted_attesters_ratio)

        yield _create_mock_signed_attestation(
            state,
            attestation_data,
            attestation_slot,
            committee,
            num_voted_attesters,
            keymap,
            config.SLOTS_PER_EPOCH,
        )
예제 #7
0
async def test_validator_get_committee_assigment(event_loop, event_bus):
    alice_indices = [7]
    alice = await get_validator(event_loop=event_loop, event_bus=event_bus, indices=alice_indices)
    state_machine = alice.chain.get_state_machine()
    state = alice.chain.get_head_state()
    epoch = compute_epoch_of_slot(state.slot, state_machine.config.SLOTS_PER_EPOCH)

    assert alice.this_epoch_assignment[alice_indices[0]][0] == -1
    alice._get_this_epoch_assignment(alice_indices[0], epoch)
    assert alice.this_epoch_assignment[alice_indices[0]][0] == epoch
예제 #8
0
def sign_transaction(*, message_hash: Hash32, privkey: int, state: BeaconState,
                     slot: Slot, signature_domain: SignatureDomain,
                     slots_per_epoch: int) -> BLSSignature:
    domain = get_domain(
        state,
        signature_domain,
        slots_per_epoch,
        message_epoch=compute_epoch_of_slot(slot, slots_per_epoch),
    )
    return bls.sign(message_hash=message_hash, privkey=privkey, domain=domain)
예제 #9
0
def _get_target_root(state: BeaconState, config: Eth2Config,
                     beacon_block_root: Hash32) -> Hash32:

    epoch = compute_epoch_of_slot(state.slot, config.SLOTS_PER_EPOCH)
    epoch_start_slot = compute_start_slot_of_epoch(epoch,
                                                   config.SLOTS_PER_EPOCH)
    if epoch_start_slot == state.slot:
        return beacon_block_root
    else:
        return get_block_root(state, epoch, config.SLOTS_PER_EPOCH,
                              config.SLOTS_PER_HISTORICAL_ROOT)
예제 #10
0
파일: loading.py 프로젝트: voith/trinity
def generate_config_by_dict(dict_config: Dict[str, Any]) -> Eth2Config:
    filtered_keys = ("DOMAIN_",
                     "EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS")

    return Eth2Config(**assoc(
        keyfilter(lambda name: all(key not in name for key in filtered_keys),
                  dict_config),
        "GENESIS_EPOCH",
        compute_epoch_of_slot(dict_config["GENESIS_SLOT"],
                              dict_config["SLOTS_PER_EPOCH"]),
    ))
예제 #11
0
def create_signed_attestation_at_slot(state: BeaconState, config: Eth2Config,
                                      state_machine: BaseBeaconStateMachine,
                                      attestation_slot: Slot,
                                      beacon_block_root: Hash32,
                                      validator_privkeys: Dict[ValidatorIndex,
                                                               int],
                                      committee: Tuple[ValidatorIndex, ...],
                                      shard: Shard) -> Attestation:
    """
    Create the attestations of the given ``attestation_slot`` slot with ``validator_privkeys``.
    """
    state_transition = state_machine.state_transition
    state = state_transition.apply_state_transition(
        state,
        future_slot=attestation_slot,
    )

    target_epoch = compute_epoch_of_slot(
        attestation_slot,
        config.SLOTS_PER_EPOCH,
    )

    target_root = _get_target_root(state, config, beacon_block_root)

    parent_crosslink = state.current_crosslinks[shard]

    attestation_data = AttestationData(
        beacon_block_root=beacon_block_root,
        source=Checkpoint(
            epoch=state.current_justified_checkpoint.epoch,
            root=state.current_justified_checkpoint.root,
        ),
        target=Checkpoint(
            root=target_root,
            epoch=target_epoch,
        ),
        crosslink=Crosslink(
            shard=shard,
            parent_root=parent_crosslink.hash_tree_root,
            start_epoch=parent_crosslink.end_epoch,
            end_epoch=target_epoch,
        ))

    return _create_mock_signed_attestation(
        state,
        attestation_data,
        attestation_slot,
        committee,
        len(committee),
        keymapper(lambda index: state.validators[index].pubkey,
                  validator_privkeys),
        config.SLOTS_PER_EPOCH,
    )
예제 #12
0
 async def handle_first_tick(self, slot: Slot) -> None:
     head = self.chain.get_canonical_head()
     state_machine = self.chain.get_state_machine()
     state = self.chain.get_head_state()
     self.logger.debug(
         # Align with debug log below
         bold_green("Head       epoch=%s slot=%s state_root=%s"),
         state.current_epoch(self.slots_per_epoch),
         head.slot,
         encode_hex(head.state_root),
     )
     self.logger.debug(
         bold_green("Justified  epoch=%s root=%s  (current)"),
         state.current_justified_checkpoint.epoch,
         encode_hex(state.current_justified_checkpoint.root),
     )
     self.logger.debug(
         bold_green("Justified  epoch=%s root=%s  (previous)"),
         state.previous_justified_checkpoint.epoch,
         encode_hex(state.previous_justified_checkpoint.root),
     )
     self.logger.debug(
         bold_green("Finalized  epoch=%s root=%s"),
         state.finalized_checkpoint.epoch,
         encode_hex(state.finalized_checkpoint.root),
     )
     self.logger.debug(
         bold_green("current_epoch_attestations  %s"),
         state.current_epoch_attestations,
     )
     self.logger.debug(
         bold_green("previous_epoch_attestations %s"),
         state.previous_epoch_attestations,
     )
     proposer_index = _get_proposer_index(
         state.copy(slot=slot, ),
         state_machine.config,
     )
     # `latest_proposed_epoch` is used to prevent validator from erraneously proposing twice
     # in the same epoch due to service crashing.
     epoch = compute_epoch_of_slot(slot, self.slots_per_epoch)
     if proposer_index in self.validator_privkeys:
         has_proposed = epoch <= self.latest_proposed_epoch[proposer_index]
         if not has_proposed:
             await self.propose_block(
                 proposer_index=proposer_index,
                 slot=slot,
                 state=state,
                 state_machine=state_machine,
                 head_block=head,
             )
             self.latest_proposed_epoch[proposer_index] = epoch
예제 #13
0
파일: loading.py 프로젝트: s0b0lev/trinity
def generate_config_by_dict(dict_config: Dict[str, Any]) -> Eth2Config:
    config_without_domains = keyfilter(lambda name: "DOMAIN_" not in name,
                                       dict_config)
    config_without_phase_1 = keyfilter(
        lambda name: "EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS" not in
        name,
        config_without_domains,
    )

    return Eth2Config(**assoc(
        config_without_phase_1, "GENESIS_EPOCH",
        compute_epoch_of_slot(
            dict_config['GENESIS_SLOT'],
            dict_config['SLOTS_PER_EPOCH'],
        )))
예제 #14
0
def _mk_attestation_for_block_with_committee(block, committee, shard, config):
    committee_count = len(committee)
    aggregation_bits = bitfield.get_empty_bitfield(committee_count)
    for index in range(committee_count):
        aggregation_bits = bitfield.set_voted(aggregation_bits, index)

    attestation = Attestation(
        aggregation_bits=aggregation_bits,
        data=AttestationData(
            beacon_block_root=block.signing_root,
            target=Checkpoint(epoch=compute_epoch_of_slot(
                block.slot, config.SLOTS_PER_EPOCH)),
            crosslink=Crosslink(shard=shard),
        ),
    )
    return attestation
예제 #15
0
def test_update_active_index_roots(genesis_state, config, state_slot,
                                   slots_per_epoch,
                                   epochs_per_historical_vector,
                                   activation_exit_delay):
    state = genesis_state.copy(slot=state_slot, )

    result = _compute_next_active_index_roots(state, config)

    index_root = ssz.get_hash_tree_root(
        get_active_validator_indices(
            state.validators,
            compute_epoch_of_slot(state.slot, slots_per_epoch),
        ),
        ssz.sedes.List(ssz.uint64, config.VALIDATOR_REGISTRY_LIMIT),
    )

    target_epoch = state.next_epoch(slots_per_epoch) + activation_exit_delay
    assert result[target_epoch % epochs_per_historical_vector] == index_root
예제 #16
0
def validate_block_header_signature(
    state: BeaconState,
    header: BeaconBlockHeader,
    pubkey: BLSPubkey,
    slots_per_epoch: int,
) -> None:
    try:
        bls.validate(
            pubkey=pubkey,
            message_hash=header.signing_root,
            signature=header.signature,
            domain=get_domain(
                state,
                SignatureDomain.DOMAIN_BEACON_PROPOSER,
                slots_per_epoch,
                compute_epoch_of_slot(header.slot, slots_per_epoch),
            ),
        )
    except SignatureError as error:
        raise ValidationError("Header signature is invalid:", error)
예제 #17
0
파일: proposer.py 프로젝트: s0b0lev/trinity
def _generate_randao_reveal(privkey: int, slot: Slot, state: BeaconState,
                            config: Eth2Config) -> BLSSignature:
    """
    Return the RANDAO reveal for the validator represented by ``privkey``.
    The current implementation requires a validator to provide the BLS signature
    over the SSZ-serialized epoch in which they are proposing a block.
    """
    epoch = compute_epoch_of_slot(slot, config.SLOTS_PER_EPOCH)

    message_hash = ssz.get_hash_tree_root(epoch, sedes=ssz.sedes.uint64)

    randao_reveal = sign_transaction(
        message_hash=message_hash,
        privkey=privkey,
        state=state,
        slot=slot,
        signature_domain=SignatureDomain.DOMAIN_RANDAO,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )
    return randao_reveal
예제 #18
0
def _introduce_collisions(all_attestations_by_index,
                          state,
                          config):
    """
    Find some attestations for later epochs for the validators
    that are current attesting in each source of attestation.
    """
    collisions = (all_attestations_by_index[0],)
    for src, dst in sliding_window(2, all_attestations_by_index):
        if not src:
            # src can be empty at low validator count
            collisions += (dst,)
            continue
        src_index = random.choice(list(src.keys()))
        src_val = src[src_index]
        src_slot, _ = src_val
        src_epoch = compute_epoch_of_slot(src_slot, config.SLOTS_PER_EPOCH)
        dst_epoch = src_epoch + 1

        collision = _find_collision(state, config, index=src_index, epoch=dst_epoch)
        collisions += (merge(dst, collision),)
    return collisions
예제 #19
0
def get_crosslink_committees_at_slot(
    state: BeaconState, slot: Slot, config: Eth2Config
) -> Tuple[Tuple[Tuple[ValidatorIndex, ...], Shard], ...]:
    epoch = compute_epoch_of_slot(slot, config.SLOTS_PER_EPOCH)
    active_validators = get_active_validator_indices(state.validators, epoch)
    committees_per_slot = (get_committee_count(
        len(active_validators),
        config.SHARD_COUNT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    ) // config.SLOTS_PER_EPOCH)
    results = []
    offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH)
    slot_start_shard = Shard(
        (get_start_shard(state, epoch, CommitteeConfig(config)) + offset) %
        config.SHARD_COUNT)
    for i in range(committees_per_slot):
        shard = (slot_start_shard + i) % config.SHARD_COUNT
        committee = get_crosslink_committee(state, epoch, shard,
                                            CommitteeConfig(config))
        results.append((committee, Shard(shard)))

    return tuple(results)
예제 #20
0
 def current_epoch(self, slots_per_epoch: int) -> Epoch:
     return compute_epoch_of_slot(self.slot, slots_per_epoch)
예제 #21
0
def test_process_crosslinks(genesis_state, config, success_in_previous_epoch,
                            success_in_current_epoch):
    shard_count = config.SHARD_COUNT
    current_slot = config.SLOTS_PER_EPOCH * 5 - 1
    current_epoch = compute_epoch_of_slot(current_slot, config.SLOTS_PER_EPOCH)
    assert current_epoch - 4 >= 0

    previous_crosslinks = tuple(
        Crosslink(
            shard=i,
            start_epoch=current_epoch - 4,
            end_epoch=current_epoch - 3,
        ) for i in range(shard_count))
    parent_crosslinks = tuple(
        Crosslink(
            shard=i,
            parent_root=previous_crosslinks[i].hash_tree_root,
            start_epoch=current_epoch - 2,
            end_epoch=current_epoch - 1,
        ) for i in range(shard_count))
    new_crosslinks = tuple(
        Crosslink(
            shard=i,
            parent_root=parent_crosslinks[i].hash_tree_root,
            start_epoch=current_epoch - 1,
            end_epoch=current_epoch,
        ) for i in range(shard_count))

    # generate expected state for correct crosslink generation
    state = genesis_state.copy(
        slot=current_slot,
        previous_crosslinks=previous_crosslinks,
        current_crosslinks=parent_crosslinks,
    )

    previous_epoch = current_epoch - 1

    expected_success_shards = set()
    previous_epoch_attestations = tuple(
        mk_all_pending_attestations_with_some_participation_in_epoch(
            state,
            previous_epoch,
            config,
            0.7 if success_in_previous_epoch else 0,
        ))
    if success_in_previous_epoch:
        for a in previous_epoch_attestations:
            expected_success_shards.add(a.data.crosslink.shard)

    current_epoch_attestations = tuple(
        mk_all_pending_attestations_with_some_participation_in_epoch(
            state,
            current_epoch,
            config,
            0.7 if success_in_current_epoch else 0,
        ))
    if success_in_current_epoch:
        for a in current_epoch_attestations:
            expected_success_shards.add(a.data.crosslink.shard)

    state = state.copy(
        previous_epoch_attestations=previous_epoch_attestations,
        current_epoch_attestations=current_epoch_attestations,
    )

    post_state = process_crosslinks(state, config)

    assert post_state.previous_crosslinks == state.current_crosslinks

    for shard in range(shard_count):
        crosslink = post_state.current_crosslinks[shard]
        if shard in expected_success_shards:
            if success_in_current_epoch:
                expected_crosslink = new_crosslinks[shard]
            else:
                expected_crosslink = parent_crosslinks[shard]
            assert crosslink == expected_crosslink
        else:
            # no change
            assert crosslink == state.current_crosslinks[shard]
예제 #22
0
def test_demo(base_db, validator_count, keymap, pubkeys, fork_choice_scoring):
    bls.use_noop_backend()
    slots_per_epoch = 8
    config = SERENITY_CONFIG._replace(
        SLOTS_PER_EPOCH=slots_per_epoch,
        GENESIS_EPOCH=compute_epoch_of_slot(SERENITY_CONFIG.GENESIS_SLOT,
                                            slots_per_epoch),
        TARGET_COMMITTEE_SIZE=3,
        SHARD_COUNT=2,
        MIN_ATTESTATION_INCLUSION_DELAY=2,
    )
    override_lengths(config)
    fixture_sm_class = SerenityStateMachine.configure(
        __name__="SerenityStateMachineForTesting", config=config)

    genesis_slot = config.GENESIS_SLOT
    genesis_epoch = config.GENESIS_EPOCH
    chaindb = BeaconChainDB(base_db, config)
    attestation_pool = AttestationPool()

    genesis_state, genesis_block = create_mock_genesis(
        pubkeys=pubkeys[:validator_count],
        config=config,
        keymap=keymap,
        genesis_block_class=SerenityBeaconBlock,
    )
    for i in range(validator_count):
        assert genesis_state.validators[i].is_active(genesis_slot)

    chaindb.persist_block(genesis_block, SerenityBeaconBlock,
                          fork_choice_scoring)
    chaindb.persist_state(genesis_state)

    state = genesis_state
    block = genesis_block

    chain_length = 3 * config.SLOTS_PER_EPOCH
    blocks = (block, )

    attestations_map = {}  # Dict[Slot, Sequence[Attestation]]

    for current_slot in range(genesis_slot + 1,
                              genesis_slot + chain_length + 1):
        if current_slot > genesis_slot + config.MIN_ATTESTATION_INCLUSION_DELAY:
            attestations = attestations_map[
                current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY]
        else:
            attestations = ()

        block = create_mock_block(
            state=state,
            config=config,
            state_machine=fixture_sm_class(chaindb, attestation_pool),
            block_class=SerenityBeaconBlock,
            parent_block=block,
            keymap=keymap,
            slot=current_slot,
            attestations=attestations,
        )

        # Get state machine instance
        sm = fixture_sm_class(chaindb, attestation_pool)
        state, _ = sm.import_block(block, state)

        chaindb.persist_state(state)
        chaindb.persist_block(block, SerenityBeaconBlock, fork_choice_scoring)

        blocks += (block, )

        # Mock attestations
        attestation_slot = current_slot
        attestations = create_mock_signed_attestations_at_slot(
            state=state,
            config=config,
            state_machine=fixture_sm_class(chaindb, attestation_pool),
            attestation_slot=attestation_slot,
            beacon_block_root=block.signing_root,
            keymap=keymap,
            voted_attesters_ratio=1.0,
        )
        attestations_map[attestation_slot] = attestations

    assert state.slot == chain_length + genesis_slot

    # Justification assertions
    assert state.current_justified_checkpoint.epoch == genesis_epoch
    assert state.finalized_checkpoint.epoch == genesis_epoch
예제 #23
0
    async def attest(self, slot: Slot) -> Tuple[Attestation, ...]:
        attestations: Tuple[Attestation, ...] = ()
        head = self.chain.get_canonical_head()
        state_machine = self.chain.get_state_machine()
        state = self.chain.get_head_state()
        epoch = compute_epoch_of_slot(slot, self.slots_per_epoch)

        validator_assignments = {
            validator_index: self._get_this_epoch_assignment(
                validator_index,
                epoch,
            )
            for validator_index in self.validator_privkeys
        }
        attesting_validators = self._get_attesting_validator_and_shard(
            validator_assignments,
            slot,
            epoch,
        )
        if len(attesting_validators) == 0:
            return ()

        # Sort the attesting validators by shard
        sorted_attesting_validators = sorted(
            attesting_validators,
            key=itemgetter(1),
        )
        # Group the attesting validators by shard
        attesting_validators_groups = groupby(
            sorted_attesting_validators,
            key=itemgetter(1),
        )
        for shard, group in attesting_validators_groups:
            # Get the validator_index -> privkey map of the attesting validators
            attesting_validator_privkeys = {
                attesting_data[0]: self.validator_privkeys[attesting_data[0]]
                for attesting_data in group
            }
            attesting_validators_indices = tuple(
                attesting_validator_privkeys.keys())
            # Get one of the attesting validator's assignment in order to get the committee info
            assignment = self._get_this_epoch_assignment(
                attesting_validators_indices[0],
                epoch,
            )
            attestation = create_signed_attestation_at_slot(
                state,
                state_machine.config,
                state_machine,
                slot,
                head.signing_root,
                attesting_validator_privkeys,
                assignment.committee,
                shard,
            )
            self.logger.debug(
                bold_green("Validators=%s attest to block=%s  attestation=%s"),
                attesting_validators_indices,
                head,
                attestation,
            )
            for validator_index in attesting_validators_indices:
                self.latest_attested_epoch[validator_index] = epoch
            attestations = attestations + (attestation, )

        self.logger.debug("Brodcasting attestations %s", attestations)
        await self.p2p_node.broadcast_attestations(attestations)
        return attestations