Example #1
0
def iterate_committees_at_slot(
    state: BeaconState, slot: Slot, committees_per_slot: int,
    config: Eth2Config
) -> Iterable[Tuple[Tuple[ValidatorIndex, ...], CommitteeIndex, Slot]]:
    """
    Iterate ``committee``, ``committee_index``, ``slot`` of the given ``slot``.
    """
    for committee_index in range(committees_per_slot):
        committee = get_beacon_committee(state, slot,
                                         CommitteeIndex(committee_index),
                                         config)
        yield committee, CommitteeIndex(committee_index), slot
Example #2
0
 def __init__(
         self,
         chain: BaseBeaconChain,
         p2p_node: Node,
         validator_privkeys: Dict[ValidatorIndex, int],
         event_bus: EndpointAPI,
         get_ready_attestations_fn: GetReadyAttestationsFn,
         get_aggregatable_attestations_fn: GetAggregatableAttestationsFn,
         import_attestation_fn: ImportAttestationFn,
         token: CancelToken = None) -> None:
     super().__init__(token)
     self.chain = chain
     self.p2p_node = p2p_node
     self.validator_privkeys = validator_privkeys
     self.event_bus = event_bus
     config = self.chain.get_state_machine().config
     self.slots_per_epoch = config.SLOTS_PER_EPOCH
     # TODO: `latest_proposed_epoch` and `latest_attested_epoch` should be written
     # into/read from validator's own db.
     self.latest_proposed_epoch = {}
     self.latest_attested_epoch = {}
     self.local_validator_epoch_assignment = {}
     for validator_index in validator_privkeys:
         self.latest_proposed_epoch[validator_index] = Epoch(-1)
         self.latest_attested_epoch[validator_index] = Epoch(-1)
         self.local_validator_epoch_assignment[validator_index] = (
             Epoch(-1),
             CommitteeAssignment((), CommitteeIndex(-1), Slot(-1)),
         )
     self.get_ready_attestations: GetReadyAttestationsFn = get_ready_attestations_fn
     self.get_aggregatable_attestations: GetAggregatableAttestationsFn = get_aggregatable_attestations_fn  # noqa: E501
     self.import_attestation: ImportAttestationFn = import_attestation_fn
Example #3
0
def get_committee_assignment(
    state: BeaconState,
    config: Eth2Config,
    epoch: Epoch,
    validator_index: ValidatorIndex,
) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``.
    ``CommitteeAssignment.committee`` is the tuple array of validators in the committee
    ``CommitteeAssignment.committee_index`` is the index to which the committee is assigned
    ``CommitteeAssignment.slot`` is the slot at which the committee is assigned
    """
    next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH)
    if epoch > next_epoch:
        raise ValidationError(
            f"Epoch for committee assignment ({epoch}) must not be after next epoch {next_epoch}."
        )

    for committee, committee_index, slot in iterate_committees_at_epoch(
        state, epoch, CommitteeConfig(config)
    ):
        if validator_index in committee:
            return CommitteeAssignment(
                committee, CommitteeIndex(committee_index), Slot(slot)
            )

    raise NoCommitteeAssignment
Example #4
0
async def _get_attestation(context: Context, request: Request) -> Response:
    if not isinstance(request, dict):
        return {}

    public_key = BLSPubkey(decode_hex(request["validator_pubkey"]))
    slot = Slot(int(request["slot"]))
    committee_index = CommitteeIndex(int(request["committee_index"]))
    attestation = context.get_attestation(public_key, slot, committee_index)
    return to_formatted_dict(attestation)
Example #5
0
 async def _get_attestation(self, request: web.Request) -> web.Response:
     # _public_key = BLSPubkey(decode_hex(request.query["validator_pubkey"]))
     slot = Slot(int(request.query["slot"]))
     committee_index = CommitteeIndex(int(request.query["committee_index"]))
     attestation = Attestation.create(
         aggregation_bits=Bitfield([True, False, False]),
         data=AttestationData.create(index=committee_index, slot=slot),
     )
     return web.json_response(to_formatted_dict(attestation))
Example #6
0
def create_mock_signed_attestations_at_slot(
    state: BeaconState,
    config: Eth2Config,
    state_machine: BaseBeaconStateMachine,
    attestation_slot: Slot,
    beacon_block_root: Root,
    keymap: Dict[BLSPubkey, int],
    voted_attesters_ratio: float = 1.0,
) -> Iterable[Attestation]:
    """
    Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``.
    """
    if voted_attesters_ratio == 0:
        return ()

    committees_per_slot = get_committee_count_at_slot(
        state,
        attestation_slot,
        config.MAX_COMMITTEES_PER_SLOT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    )

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

    for committee, committee_index, _ in iterate_committees_at_slot(
            state, attestation_slot, committees_per_slot, config):
        attestation_data = AttestationData.create(
            slot=attestation_slot,
            index=CommitteeIndex(committee_index),
            beacon_block_root=beacon_block_root,
            source=Checkpoint.create(
                epoch=state.current_justified_checkpoint.epoch,
                root=state.current_justified_checkpoint.root,
            ),
            target=Checkpoint.create(root=target_root, epoch=target_epoch),
        )

        num_voted_attesters = max(int(len(committee) * voted_attesters_ratio),
                                  1)

        yield _create_mock_signed_attestation(
            state,
            attestation_data,
            attestation_slot,
            committee,
            num_voted_attesters,
            keymap,
            config.SLOTS_PER_EPOCH,
        )
Example #7
0
def _get_mock_attesting_indices(
        committee: Sequence[ValidatorIndex],
        num_voted_attesters: int) -> Tuple[CommitteeIndex, ...]:
    """
    Get voting indices of the given ``committee``.
    """
    committee_size = len(committee)
    assert num_voted_attesters <= committee_size

    attesting_indices = tuple(
        CommitteeIndex(i)
        for i in random.sample(range(committee_size), num_voted_attesters))

    return tuple(sorted(attesting_indices))
Example #8
0
def _get_mock_message_and_attesting_indices(
        attestation_data: AttestationData, committee: Sequence[ValidatorIndex],
        num_voted_attesters: int) -> Tuple[Hash32, Tuple[CommitteeIndex, ...]]:
    """
    Get ``message_hash`` and voting indices of the given ``committee``.
    """
    message_hash = AttestationDataAndCustodyBit(
        data=attestation_data, custody_bit=False).hash_tree_root

    committee_size = len(committee)
    assert num_voted_attesters <= committee_size

    attesting_indices = tuple(
        CommitteeIndex(i)
        for i in random.sample(range(committee_size), num_voted_attesters))

    return message_hash, tuple(sorted(attesting_indices))
Example #9
0
    def duty_fetcher(current_tick, _public_keys, target_epoch,
                     _slots_per_epoch, _seconds_per_slot):
        duties = ()
        if target_epoch < 0:
            return duties

        some_slot = current_tick.slot
        if current_tick.epoch >= 0:
            block_proposal_duty = BlockProposalDuty(
                public_key, Tick(0, some_slot, target_epoch, 0), current_tick)
            duties += (block_proposal_duty, )
        attestation_duty = AttestationDuty(
            public_key,
            Tick(0, some_slot + slots_per_epoch, target_epoch, 1),
            current_tick,
            CommitteeIndex(22),
        )
        duties += (attestation_duty, )
        return duties
Example #10
0
def _parse_attestation_duty(
    duty_data: Dict[str, Any],
    validator_public_key: BLSPubkey,
    current_tick: Tick,
    target_epoch: Epoch,
    genesis_time: int,
    seconds_per_slot: int,
    ticks_per_slot: int,
) -> AttestationDuty:
    target_tick = Tick.computing_t_from(
        Slot(duty_data["attestation_slot"]),
        target_epoch,
        AttestationDuty.tick_count,
        genesis_time,
        seconds_per_slot,
        ticks_per_slot,
    )
    return AttestationDuty(
        validator_public_key=validator_public_key,
        tick_for_execution=target_tick,
        discovered_at_tick=current_tick,
        committee_index=CommitteeIndex(duty_data["committee_index"]),
    )
Example #11
0
def _fetch_some_random_duties(
    current_tick: Tick,
    public_keys: Collection[BLSPubkey],
    target_epoch: Epoch,
    slots_per_epoch: Slot,
    seconds_per_slot: int,
) -> Tuple[Duty, ...]:
    if not public_keys:
        return ()
    if target_epoch < 0:
        return ()
    some_slot = Slot(
        random.randint(0, slots_per_epoch) + target_epoch * slots_per_epoch)
    execution_time = seconds_per_slot * (some_slot -
                                         current_tick.slot) + current_tick.t
    is_attestation = bool(random.getrandbits(1))
    # NOTE: use of ``tuple`` here is satisfy ``mypy``.
    some_validator = random.choice(tuple(public_keys))
    if is_attestation:
        committee_index = random.randint(0, 64)
        some_tick_count = 1
        attestation_duty = AttestationDuty(
            some_validator,
            Tick(execution_time, some_slot, target_epoch, some_tick_count),
            current_tick,
            CommitteeIndex(committee_index),
        )
        return (attestation_duty, )
    else:
        some_tick_count = 0
        block_proposal_duty = BlockProposalDuty(
            some_validator,
            Tick(execution_time, some_slot, target_epoch, some_tick_count),
            current_tick,
        )
        return (block_proposal_duty, )
Example #12
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, )

    # 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_at_epoch(state.current_justified_checkpoint.epoch,
                                    config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_HISTORICAL_ROOT,
    )

    committees_per_slot = get_committee_count_at_slot(
        state,
        Slot(attestation_slot),
        config.MAX_COMMITTEES_PER_SLOT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    )
    # Use the first committee
    assert committees_per_slot > 0
    committee_index = CommitteeIndex(0)

    attestation_data = AttestationData.create(
        slot=attestation_slot,
        index=committee_index,
        beacon_block_root=beacon_block_root,
        source=Checkpoint.create(
            epoch=state.current_justified_checkpoint.epoch, root=source_root),
        target=Checkpoint.create(
            epoch=compute_epoch_at_slot(attestation_slot,
                                        config.SLOTS_PER_EPOCH),
            root=target_root,
        ),
    )

    message_hash = attestation_data.hash_tree_root
    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_BEACON_ATTESTER,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )
    validator_indices = tuple(committee[i] for i in attesting_indices)

    return IndexedAttestation.create(attesting_indices=validator_indices,
                                     data=attestation_data,
                                     signature=signature)
Example #13
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,
                tuple(
                    CommitteeIndex(assignment.committee.index(index))
                    for index in attesting_validators_indices),
            )
            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

            self.logger.debug("Broadcasting attestation %s", attestation)
            await self.p2p_node.broadcast_attestation(attestation)

            attestations = attestations + (attestation, )
        # TODO: Aggregate attestations

        return attestations
Example #14
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_without_block(
        state,
        attestation_slot,
    )

    # Get `target_root`
    target_root = _get_target_root(state, config, beacon_block_root)

    previous_crosslink = state.latest_crosslinks[shard]

    attestation_data = AttestationData(
        slot=attestation_slot,
        beacon_block_root=beacon_block_root,
        source_epoch=state.current_justified_epoch,
        source_root=state.current_justified_root,
        target_root=target_root,
        shard=shard,
        previous_crosslink=previous_crosslink,
        crosslink_data_root=ZERO_HASH32,
    )

    message_hash = AttestationDataAndCustodyBit(data=attestation_data,
                                                custody_bit=False).root

    signatures = [
        sign_transaction(
            message_hash=message_hash,
            privkey=privkey,
            fork=state.fork,
            slot=attestation_data.slot,
            signature_domain=SignatureDomain.DOMAIN_ATTESTATION,
            slots_per_epoch=config.SLOTS_PER_EPOCH,
        ) for _, privkey in validator_privkeys.items()
    ]

    voting_committee_indices = [
        CommitteeIndex(committee.index(validator_index))
        for validator_index in validator_privkeys
    ]
    # aggregate signatures and construct participant bitfield
    aggregation_bitfield, aggregate_signature = aggregate_votes(
        bitfield=get_empty_bitfield(len(committee)),
        sigs=(),
        voting_sigs=signatures,
        voting_committee_indices=voting_committee_indices,
    )

    # create attestation from attestation_data, particpipant_bitfield, and signature
    return Attestation(
        aggregation_bitfield=aggregation_bitfield,
        data=attestation_data,
        custody_bitfield=Bitfield(get_empty_bitfield(
            len(aggregation_bitfield))),
        aggregate_signature=aggregate_signature,
    )