示例#1
0
    def update_time(self, frequency=frequency) -> None:
        # Moving validators' clocks by one step
        # To keep it simple, we assume frequency is a power of ten (see `assert` above)
        self.data.time_ms = self.data.time_ms + int(1000 / frequency)
        if self.data.time_ms % 1000 == 0:
            # The store is updated each second in the specs
            specs.on_tick(self.store, self.store.time + 1)

            # If a new slot starts, we update
            if specs.get_current_slot(self.store) != self.data.slot:
                self.update_data()
示例#2
0
    def __init__(self, state, validator_index):
        # Validator constructor
        # We preload a bunch of things, to be updated later on as needed
        # The validator is initialised from some base state, and given a `validator_index`
        self.validator_index = validator_index

        self.store = specs.get_forkchoice_store(state)
        self.history = []

        self.data = ValidatorData()
        self.data.time_ms = self.store.time * 1000
        self.data.recorded_attestations = []

        self.data.slot = specs.get_current_slot(self.store)
        self.data.current_epoch = specs.compute_epoch_at_slot(self.data.slot)

        self.data.head_root = self.get_head()
        current_state = state.copy()
        if current_state.slot < self.data.slot:
            specs.process_slots(current_state, self.data.slot)

        self.update_attester(current_state, self.data.current_epoch)
        self.update_proposer(current_state)
        self.update_data()
示例#3
0
    def update_data(self) -> None:
        # The head may change if we recorded a new block/new attestation
        # Attester/proposer responsibilities may change if head changes *and*
        # canonical chain changes to further back from start current epoch
        #
        # ---x------
        #    \        x is fork point
        #     -----
        #
        # In the following attester = attester responsibilities for current epoch
        #                  proposer = proposer responsibilities for current epoch
        #
        # - If x after current epoch change (---|--x , | = start current epoch), proposer and attester don't change
        # - If x between start of previous epoch and start of current epoch (--||--x---|-- , || = start previous epoch)
        #   proposer changes but not attester
        # - If x before start of previous epoch (--x--||-----|----) both proposer and attester change

        slot = specs.get_current_slot(self.store)
        new_slot = self.data.slot != slot

        # Current epoch in validator view
        current_epoch = specs.compute_epoch_at_slot(slot)

        self.update_attest_move()
        self.update_propose_move()

        # Did the validator receive a block in this slot?
        received_block = len([
            block for block_root, block in self.store.blocks.items()
            if block.slot == slot
        ]) > 0

        if not new_slot:
            # It's not a new slot, we are here because a new block/attestation was received

            # Getting the current state, fast-forwarding from the head
            head_root = self.get_head()

            if self.data.head_root != head_root:
                lca = lowest_common_ancestor(self.store, self.data.head_root,
                                             head_root)
                lca_epoch = specs.compute_epoch_at_slot(lca.slot)

                if lca_epoch == current_epoch:
                    # do nothing
                    pass
                else:
                    current_state = self.process_to_slot(head_root, slot)
                    if lca_epoch == current_epoch - 1:
                        self.update_proposer(current_state)
                    else:
                        self.update_proposer(current_state)
                        self.update_attester(current_state, current_epoch)
                self.data.head_root = head_root

        else:
            # It's a new slot. We should update our proposer/attester duties
            # if it's also a new epoch. If not we do nothing.
            if self.data.current_epoch != current_epoch:
                current_state = self.process_to_slot(self.data.head_root, slot)

                # We need to check our proposer role for this new epoch
                self.update_proposer(current_state)

                # We need to check our attester role for this new epoch
                self.update_attester(current_state, current_epoch)

        self.data.slot = slot
        self.data.current_epoch = current_epoch
        self.data.received_block = received_block