Esempio n. 1
0
    def get_validator_duties(self, public_keys: Collection[BLSPubkey],
                             epoch: Epoch) -> Iterable[ValidatorDuty]:
        if epoch < GENESIS_EPOCH:
            return ()

        current_tick = self.clock.compute_current_tick()
        state = advance_state_to_slot(self.chain, current_tick.slot)
        for public_key in public_keys:
            validator_index = state.get_validator_index_for_public_key(
                public_key)
            try:
                committee_assignment = get_committee_assignment(
                    state, self.eth2_config, epoch, validator_index)
            except NoCommitteeAssignment:
                continue

            if is_proposer(state, validator_index, self.eth2_config):
                # TODO (ralexstokes) clean this up!
                if state.slot != 0:
                    block_proposal_slot = state.slot
                else:
                    block_proposal_slot = Slot((1 << 64) - 1)
            else:
                # NOTE: temporary sentinel value for "no slot"
                # The API has since been updated w/ much better ergonomics
                block_proposal_slot = Slot((1 << 64) - 1)
            yield ValidatorDuty(
                public_key,
                committee_assignment.slot,
                committee_assignment.committee_index,
                block_proposal_slot,
            )
Esempio n. 2
0
def get_committee_assignment(
        state: BeaconState,
        config: BeaconConfig,
        epoch: Epoch,
        validator_index: ValidatorIndex,
        registry_change: bool = False) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``
    and ``registry_change``.
    ``CommitteeAssignment.committee`` is the tuple array of validators in the committee
    ``CommitteeAssignment.shard`` is the shard to which the committee is assigned
    ``CommitteeAssignment.slot`` is the slot at which the committee is assigned
    ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to
        propose a beacon block at the assigned slot.
    """
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)
    next_epoch = Epoch(current_epoch + 1)

    validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch)

    epoch_start_slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH)

    committee_config = CommitteeConfig(config)

    for slot in range(epoch_start_slot,
                      epoch_start_slot + config.SLOTS_PER_EPOCH):
        crosslink_committees = get_crosslink_committees_at_slot(
            state,
            slot,
            committee_config,
            registry_change=registry_change,
        )
        selected_committees = [
            committee for committee in crosslink_committees
            if validator_index in committee[0]
        ]
        if len(selected_committees) > 0:
            validators = selected_committees[0][0]
            shard = selected_committees[0][1]
            is_proposer = validator_index == get_beacon_proposer_index(
                state,
                Slot(slot),
                committee_config,
                registry_change=registry_change,
            )

            return CommitteeAssignment(validators, shard, Slot(slot),
                                       is_proposer)

    raise NoCommitteeAssignment
Esempio n. 3
0
    def _read_state_randao_mixes(self, state_root: Root,
                                 EPOCHS_PER_HISTORICAL_VECTOR: int,
                                 SLOTS_PER_EPOCH: int) -> Iterable[Root]:
        """
        Reconstructs the ``randao_mixes`` at a given state root.
        """
        state_slot = self._read_state_slot(state_root)
        state_epoch = compute_epoch_at_slot(state_slot, SLOTS_PER_EPOCH)

        finalized_slot = self.get_finalized_head(BeaconBlock).slot
        non_finalized_state_roots = dict(
            enumerate(
                self.get_state_parents(state_root,
                                       state_slot - finalized_slot),
                finalized_slot,
            ))

        # create a list of epochs that corresponds to each mix in ``state.randao_mixes``
        epochs = [
            Epoch(n)
            for n in range(state_epoch - EPOCHS_PER_HISTORICAL_VECTOR +
                           1, state_epoch + 1)
        ]
        offset = EPOCHS_PER_HISTORICAL_VECTOR - epochs[
            0] % EPOCHS_PER_HISTORICAL_VECTOR
        epochs = epochs[offset:] + epochs[:offset]

        genesis_root = self._read_state_root_at_slot(Slot(0))
        genesis_randao_mix = Root(
            Hash32(self.db[SchemaV1.state_root_to_randao_mix(genesis_root)]))

        for epoch in epochs:
            if epoch < 0:
                yield genesis_randao_mix
            elif epoch == state_epoch:
                # yield the randao mix at the particular slot
                key = SchemaV1.state_root_to_randao_mix(state_root)
                yield Root(Hash32(self.db[key]))
            else:
                # yield the randao mix at the last slot in the epoch
                slot = Slot((epoch + 1) * SLOTS_PER_EPOCH - 1)
                if slot in non_finalized_state_roots:
                    root = non_finalized_state_roots[slot]
                else:
                    root = self._read_state_root_at_slot(slot)

                key = SchemaV1.state_root_to_randao_mix(root)
                yield Root(Hash32(self.db[key]))
Esempio n. 4
0
def compute_slots_since_epoch_start(slot: Slot, slots_per_epoch: int) -> Slot:
    return Slot(
        slot
        - compute_start_slot_at_epoch(
            compute_epoch_at_slot(slot, slots_per_epoch), slots_per_epoch
        )
    )
Esempio n. 5
0
 def _find_present_ancestor_state(
         self, block_root: Root
 ) -> Tuple[BeaconState, Tuple[SignedBeaconBlock, ...]]:
     """
     Find the first state we have persisted that is an ancestor of ``target_block``.
     """
     try:
         block = self._chain_db.get_block_by_root(block_root, BeaconBlock)
         blocks: Tuple[SignedBeaconBlock, ...] = ()
         # NOTE: re: bounds here; worst case, we return the genesis state.
         for slot in range(block.slot, GENESIS_SLOT - 1, -1):
             try:
                 state_machine = self.get_state_machine(Slot(slot))
                 state = self._chain_db.get_state_by_root(
                     block.state_root,
                     state_machine.state_class,
                     state_machine.config,
                 )
                 return (state, blocks)
             except StateNotFound:
                 signature = self._chain_db.get_block_signature_by_root(
                     block.hash_tree_root)
                 blocks += (SignedBeaconBlock.create(message=block,
                                                     signature=signature), )
                 block = self._chain_db.get_block_by_root(
                     block.parent_root, BeaconBlock)
     except BlockNotFound:
         raise Exception(
             "invariant violated: querying a block that has not been persisted"
         )
     # NOTE: `mypy` complains without this although execution should never get here...
     return (None, ())
Esempio n. 6
0
    async def _keep_ticking(self) -> None:
        """
        Ticker should tick three times in one slot:
        SLOT_START: at the beginning of the slot
        SLOT_ONE_THIRD: at 1/3 of the slot
        SLOT_TWO_THIRD: at 2/3 of the slot
        """
        # Use `sent_tick_types_at_slot` set to record
        # the tick types that haven been sent at current slot.
        sent_tick_types_at_slot: Set[TickType] = set()
        while self.is_operational:
            elapsed_time = Second(int(time.time()) - self.genesis_time)

            # Skip genesis slot
            if elapsed_time < self.seconds_per_slot:
                continue

            elapsed_slots = elapsed_time // self.seconds_per_slot
            slot = Slot(elapsed_slots + self.genesis_slot)
            tick_type = self._get_tick_type(elapsed_time)

            # New slot
            if slot > self.latest_slot:
                self.latest_slot = slot
                await self._broadcast_slot_tick_event(slot, elapsed_time,
                                                      tick_type)
                # Clear set
                sent_tick_types_at_slot = set()
                sent_tick_types_at_slot.add(TickType.SLOT_START)
            elif not tick_type.is_start and tick_type not in sent_tick_types_at_slot:
                await self._broadcast_slot_tick_event(slot, elapsed_time,
                                                      tick_type)
                sent_tick_types_at_slot.add(tick_type)

            await asyncio.sleep(self.seconds_per_slot // self.check_frequency)
Esempio n. 7
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
Esempio n. 8
0
def create_mock_attester_slashing_is_surround_vote(
        state: BeaconState, config: BeaconConfig, keymap: Dict[BLSPubkey, int],
        attestation_epoch: Epoch) -> AttesterSlashing:
    # target_epoch_2 < target_epoch_1
    attestation_slot_2 = get_epoch_start_slot(attestation_epoch,
                                              config.SLOTS_PER_EPOCH)
    attestation_slot_1 = Slot(attestation_slot_2 + config.SLOTS_PER_EPOCH)

    slashable_attestation_1 = create_mock_slashable_attestation(
        state.copy(
            slot=attestation_slot_1,
            justified_epoch=config.GENESIS_EPOCH,
        ),
        config,
        keymap,
        attestation_slot_1,
    )
    slashable_attestation_2 = create_mock_slashable_attestation(
        state.copy(
            slot=attestation_slot_1,
            justified_epoch=config.GENESIS_EPOCH +
            1,  # source_epoch_1 < source_epoch_2
        ),
        config,
        keymap,
        attestation_slot_2,
    )

    return AttesterSlashing(
        slashable_attestation_1=slashable_attestation_1,
        slashable_attestation_2=slashable_attestation_2,
    )
Esempio n. 9
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__(
            chain,
            p2p_node,
            event_bus,
            get_ready_attestations_fn,
            get_aggregatable_attestations_fn,
            import_attestation_fn,
            token,
        )

        self.validator_privkeys = validator_privkeys
        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)),
            )
Esempio n. 10
0
def create_block_header_with_signature(
    state: BeaconState,
    body_root: Root,
    privkey: int,
    slots_per_epoch: int,
    proposer_index: ValidatorIndex,
    parent_root: Root = SAMPLE_HASH_1,
    state_root: Root = SAMPLE_HASH_2,
) -> SignedBeaconBlockHeader:
    block_header = BeaconBlockHeader.create(
        slot=Slot(state.slot),
        proposer_index=proposer_index,
        parent_root=parent_root,
        state_root=state_root,
        body_root=body_root,
    )
    block_header_signature = sign_transaction(
        object=block_header,
        privkey=privkey,
        state=state,
        slot=block_header.slot,
        signature_domain=SignatureDomain.DOMAIN_BEACON_PROPOSER,
        slots_per_epoch=slots_per_epoch,
    )
    return SignedBeaconBlockHeader.create(message=block_header,
                                          signature=block_header_signature)
Esempio n. 11
0
def create_mock_attester_slashing_is_double_vote(
        state: BeaconState,
        config: Eth2Config,
        keymap: Dict[BLSPubkey, int],
        attestation_epoch: Epoch) -> AttesterSlashing:
    attestation_slot_1 = get_epoch_start_slot(attestation_epoch, config.SLOTS_PER_EPOCH)
    attestation_slot_2 = Slot(attestation_slot_1 + 1)

    slashable_attestation_1 = create_mock_slashable_attestation(
        state,
        config,
        keymap,
        attestation_slot_1,
    )
    slashable_attestation_2 = create_mock_slashable_attestation(
        state,
        config,
        keymap,
        attestation_slot_2,
    )

    return AttesterSlashing(
        slashable_attestation_1=slashable_attestation_1,
        slashable_attestation_2=slashable_attestation_2,
    )
Esempio n. 12
0
 def __init__(self,
              chain: BeaconChain,
              p2p_node: Node,
              validator_privkeys: Dict[ValidatorIndex, int],
              event_bus: EndpointAPI,
              get_ready_attestations_fn: GetReadyAttestationsFn,
              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.this_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.this_epoch_assignment[validator_index] = (
             Epoch(-1),
             CommitteeAssignment((), Shard(-1), Slot(-1), False),
         )
     self.get_ready_attestations: GetReadyAttestationsFn = get_ready_attestations_fn
Esempio n. 13
0
def main_validator() -> None:
    # TODO:
    # Merge into trinity platform
    # 1. CLI parsing
    # 2. Loading config from file and/or cmd line
    # 3. Logging
    logger = _setup_logging()
    arguments = parse_cli_args()
    root_data_dir = (Path(os.environ["HOME"]) / ".local" / "share" /
                     "trinity" / "eth2" / "validator_client")
    slots_per_epoch = Slot(4)
    seconds_per_slot = 2
    genesis_time = int(time.time()) + slots_per_epoch * seconds_per_slot + 3
    num_validators = 16
    key_pairs = tuple(
        _mk_random_key_pair(index) for index in range(num_validators))

    config = Config(
        key_store_constructor=_mk_key_store_from_key_pairs(key_pairs),
        root_data_dir=root_data_dir,
        slots_per_epoch=slots_per_epoch,
        seconds_per_slot=seconds_per_slot,
        genesis_time=genesis_time,
        demo_mode=arguments.demo_mode,
    )
    trio.run(arguments.func, logger, config, arguments)
Esempio n. 14
0
def create_mock_attester_slashing_is_surround_vote(
    state: BeaconState,
    config: Eth2Config,
    keymap: Dict[BLSPubkey, int],
    attestation_epoch: Epoch,
) -> AttesterSlashing:
    # target_epoch_2 < target_epoch_1
    attestation_slot_2 = compute_start_slot_at_epoch(attestation_epoch,
                                                     config.SLOTS_PER_EPOCH)
    attestation_slot_1 = Slot(attestation_slot_2 + config.SLOTS_PER_EPOCH)

    slashable_attestation_1 = create_mock_slashable_attestation(
        state.mset("slot", attestation_slot_1, "current_justified_epoch",
                   config.GENESIS_EPOCH),
        config,
        keymap,
        attestation_slot_1,
    )
    slashable_attestation_2 = create_mock_slashable_attestation(
        state.mset(
            "slot",
            attestation_slot_1,
            "current_justified_epoch",
            config.GENESIS_EPOCH + 1,  # source_epoch_1 < source_epoch_2
        ),
        config,
        keymap,
        attestation_slot_2,
    )

    return AttesterSlashing.create(attestation_1=slashable_attestation_1,
                                   attestation_2=slashable_attestation_2)
Esempio n. 15
0
 def get_batches(self, max_size: int) -> Iterable["SyncRequest"]:
     last_slot = self.start_slot + self.count
     batch_offsets = range(self.start_slot, self.start_slot + self.count,
                           max_size)
     for offset in batch_offsets:
         remainder = last_slot - offset
         batch_size = max_size if remainder > max_size else remainder
         yield self.__class__(self.peer_id, Slot(offset), batch_size)
Esempio n. 16
0
class StateTestCase(BaseTestCase):
    bls_setting: bool
    description: str
    pre: BeaconState
    post: BeaconState
    slots: Slot = Slot(0)
    blocks: Tuple[BeaconBlock, ...] = field(default_factory=tuple)
    is_valid: bool = True
Esempio n. 17
0
 async def _get_block_proposal(self, request: web.Request) -> web.Response:
     slot = Slot(int(request.query["slot"]))
     randao_reveal = BLSSignature(
         decode_hex(request.query["randao_reveal"]).ljust(96, b"\x00"))
     block = BeaconBlock.create(
         slot=slot,
         body=BeaconBlockBody.create(randao_reveal=randao_reveal))
     return web.json_response(to_formatted_dict(block))
Esempio n. 18
0
    async def block(self, request: web.Request) -> Dict[str, Any]:
        if 'slot' in request.query:
            slot = Slot(int(request.query['slot']))
            block = self.chain.get_canonical_block_by_slot(slot)
        elif 'root' in request.query:
            root = cast(Root, decode_hex(request.query['root']))
            block = self.chain.get_block_by_root(root)

        return to_formatted_dict(block, sedes=BeaconBlock)
Esempio n. 19
0
 def _compute_slot_and_alignment(self, t: float) -> Tuple[Slot, bool]:
     """
     Compute the slot corresponding to a time ``t``.
     Indicate if ``t`` corresponds to the first tick in the relevant slot
     with a boolean return value.
     """
     time_since_genesis = t - self._genesis_time
     slot, sub_slot = divmod(time_since_genesis, self._seconds_per_slot)
     return (Slot(int(slot)), int(sub_slot * self._tick_multiplier) == 0)
Esempio n. 20
0
 def _get_slot_by_root(db: DatabaseAPI, block_root: Hash32) -> Slot:
     validate_word(block_root, title="block root")
     try:
         encoded_slot = db[SchemaV1.make_block_root_to_slot_lookup_key(
             block_root)]
     except KeyError:
         raise BlockNotFound("No block with root {0} found".format(
             encode_hex(block_root)))
     return Slot(ssz.decode(encoded_slot, sedes=ssz.sedes.uint64))
Esempio n. 21
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)
Esempio n. 22
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))
Esempio n. 23
0
    def beacon_attestation_validator(msg_forwarder: ID,
                                     msg: rpc_pb2.Message) -> bool:
        try:
            attestation = ssz.decode(msg.data, sedes=Attestation)
        except (TypeError, ssz.DeserializationError) as error:
            # Not correctly encoded
            logger.debug(
                bold_red("Failed to validate attestation=%s, error=%s"),
                attestation,
                str(error),
            )
            return False

        state_machine = chain.get_state_machine()
        config = state_machine.config
        state = chain.get_head_state()

        # Check that beacon blocks attested to by the attestation are validated
        try:
            chain.get_block_by_root(attestation.data.beacon_block_root)
        except BlockNotFound:
            logger.debug(
                bold_red(
                    "Failed to validate attestation=%s, attested block=%s is not validated yet"
                ),
                attestation,
                encode_hex(attestation.data.beacon_block_root),
            )
            return False

        # Fast forward to state in future slot in order to pass
        # attestation.data.slot validity check
        attestation_data_slot = get_attestation_data_slot(
            state,
            attestation.data,
            config,
        )
        future_state = state_machine.state_transition.apply_state_transition(
            state,
            future_slot=Slot(attestation_data_slot +
                             config.MIN_ATTESTATION_INCLUSION_DELAY),
        )
        try:
            validate_attestation(
                future_state,
                attestation,
                config,
            )
        except ValidationError as error:
            logger.debug(
                bold_red("Failed to validate attestation=%s, error=%s"),
                attestation,
                str(error),
            )
            return False

        return True
Esempio n. 24
0
def test_chain2_full(base_db, genesis_state, config):
    chain_db = BeaconChainDB.from_genesis(base_db, genesis_state,
                                          SignedBeaconBlock, config)

    state = genesis_state
    states = [genesis_state]
    blocks = {}

    num_slots = 500
    skip_slots = [5, 64, 100, 300, 301, 302, 401]
    finalized_slots = [8, 24, 32, 72, 152, 160, 328, 336, 344, 352, 400]

    # create a new state at each slot using ``_mini_stf()`` and persist it
    for _ in range(1, num_slots):
        if state.slot not in skip_slots:
            new_block = BeaconBlock.create(slot=state.slot,
                                           state_root=state.hash_tree_root)
            blocks[state.slot] = new_block
            chain_db.persist_block(SignedBeaconBlock.create(message=new_block))
        else:
            new_block = None

        state = _mini_stf(state, new_block, config)
        chain_db.persist_state(state, config)
        states.append(state)

    # test that each state created above equals the state stored at its root
    for state in states:
        # finalize a slot two epochs after processing it
        # this is here to test the reconstruction of ``state.randao_mixes``
        maybe_finalized_slot = state.slot - config.SLOTS_PER_EPOCH * 2
        if maybe_finalized_slot in finalized_slots:
            chain_db.mark_finalized_head(blocks[maybe_finalized_slot])

        retrieved_state = chain_db._read_state(state.hash_tree_root,
                                               BeaconState, config)
        assert retrieved_state == state

    for slot in range(0, num_slots):
        if slot in blocks and slot <= finalized_slots[-1]:
            assert chain_db.get_block_by_slot(Slot(slot),
                                              BeaconBlock) == blocks[slot]
        else:
            assert chain_db.get_block_by_slot(Slot(slot), BeaconBlock) is None
Esempio n. 25
0
    async def state(self, request: web.Request) -> Dict[str, Any]:
        if 'slot' in request.query:
            slot = Slot(int(request.query['slot']))
            state = self.chain.get_state_by_slot(slot)
        elif 'root' in request.query:
            root = cast(Root, decode_hex(request.query['root']))
            state = self.chain.get_state_by_root(root)
        else:
            raise APIServerError(f"Wrong querystring: {request.query}")

        return to_formatted_dict(state)
Esempio n. 26
0
 def _determine_sync_requests(self, peer_id: PeerID,
                              status: Status) -> Iterable[SyncRequest]:
     """
     If the peer has a higher finalized epoch or head slot, sync blocks from them.
     """
     head_state = self._chain.get_canonical_head_state()
     finalized_slot = compute_start_slot_at_epoch(
         head_state.finalized_checkpoint.epoch,
         self._eth2_config.SLOTS_PER_EPOCH)
     while finalized_slot < status.head_slot:
         count = min(status.head_slot - finalized_slot, MAX_REQUEST_BLOCKS)
         yield SyncRequest(peer_id, Slot(finalized_slot + 1), count)
         finalized_slot += count
Esempio n. 27
0
async def _get_block_proposal(context: Context, request: Request) -> Response:
    if not isinstance(request, dict):
        return {}

    slot = Slot(int(request["slot"]))
    randao_reveal = BLSSignature(
        decode_hex(request["randao_reveal"]).ljust(96, b"\x00"))
    try:
        block = context.get_block_proposal(slot, randao_reveal)
        return to_formatted_dict(block)
    except Exception as e:
        # TODO error handling...
        return {"error": str(e)}
Esempio n. 28
0
def advance_state_to_slot(chain: BaseBeaconChain,
                          target_slot: Slot,
                          state: BeaconState = None) -> BeaconState:
    if state is None:
        state = chain.get_canonical_head_state()

    current_slot = state.slot
    for slot in range(current_slot, target_slot + 1):
        slot = Slot(slot)
        state_machine = chain.get_state_machine(slot)
        state, _ = state_machine.apply_state_transition(state,
                                                        future_slot=slot)
    return state
Esempio n. 29
0
 def _determine_sync_request(self, peer_id: PeerID,
                             status: Status) -> Optional[SyncRequest]:
     """
     If the peer has a higher finalized epoch or head slot, sync blocks from them.
     """
     head_state = self._chain.get_canonical_head_state()
     finalized_slot = compute_start_slot_at_epoch(
         head_state.finalized_checkpoint.epoch,
         self._eth2_config.SLOTS_PER_EPOCH)
     if finalized_slot < status.head_slot:
         span = status.head_slot - finalized_slot
         return SyncRequest(peer_id, Slot(finalized_slot + 1), span)
     else:
         return None
Esempio n. 30
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.shard`` is the shard to which the committee is assigned
    ``CommitteeAssignment.slot`` is the slot at which the committee is assigned
    ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to
        propose a beacon block at the assigned slot.
    """
    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}."
        )

    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
    )
    epoch_start_slot = compute_start_slot_of_epoch(epoch, config.SLOTS_PER_EPOCH)
    epoch_start_shard = get_start_shard(state, epoch, CommitteeConfig(config))

    for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH):
        offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH)
        slot_start_shard = (epoch_start_shard + offset) % config.SHARD_COUNT
        for i in range(committees_per_slot):
            shard = Shard((slot_start_shard + i) % config.SHARD_COUNT)
            committee = get_crosslink_committee(
                state, epoch, shard, CommitteeConfig(config)
            )
            if validator_index in committee:
                is_proposer = validator_index == get_beacon_proposer_index(
                    state.copy(slot=slot), CommitteeConfig(config)
                )
                return CommitteeAssignment(
                    committee, Shard(shard), Slot(slot), is_proposer
                )

    raise NoCommitteeAssignment