def lowest_common_ancestor(store, old_head, new_head) -> Optional[specs.BeaconBlock]: # in most cases, old_head <- new_head # we sort of (loosely) optimise for this new_head_ancestors = [new_head] current_block = store.blocks[new_head] keep_searching = True while keep_searching: parent_root = current_block.parent_root parent_block = store.blocks[parent_root] if parent_root == old_head: return store.blocks[old_head] elif parent_block.slot == 0 or \ specs.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) > specs.compute_epoch_at_slot(parent_block.slot): keep_searching = False else: new_head_ancestors += [parent_root] current_block = parent_block # At this point, old_head wasn't an ancestor to new_head # We need to find old_head's ancestors current_block = store.blocks[old_head] keep_searching = True while keep_searching: parent_root = current_block.parent_root parent_block = store.blocks[parent_root] if parent_root in new_head_ancestors: return parent_block elif parent_root == Bytes32() or \ specs.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) < specs.compute_epoch_at_slot(parent_block.slot): return None
def update_proposer(self, current_state): # This is a fairly expensive operation, so we try not to call it when we don't have to. # Update proposer duties for the current epoch. # We need to check for each slot of the epoch whether the validator is a proposer or not. current_epoch = specs.get_current_epoch(current_state) start_slot = specs.compute_start_slot_at_epoch(current_epoch) start_state = current_state.copy() if start_slot == current_state.slot else \ self.store.block_states[specs.get_block_root(current_state, current_epoch)].copy() current_proposer_duties = [] for slot in range(start_slot, start_slot + specs.SLOTS_PER_EPOCH): if slot < start_state.slot: current_proposer_duties += [False] continue if start_state.slot < slot: specs.process_slots(start_state, slot) current_proposer_duties += [ specs.get_beacon_proposer_index(start_state) == self.validator_index ] self.data.current_proposer_duties = current_proposer_duties
def honest_attest_policy(params, step, sL, s): # Collect all attestations formed for slot s. # `state` is at w-[s+1] state = s['beacon_state'] current_epoch = get_current_epoch(state) previous_epoch = get_previous_epoch(state) # `validator_epoch` is the epoch of slot s. # - If the state is already ahead by one epoch, this is given by `previous_epoch` # - Otherwise it is `current_epoch` if state.slot == compute_start_slot_at_epoch(current_epoch): validator_epoch = previous_epoch else: validator_epoch = current_epoch active_validator_indices = get_active_validator_indices( state, validator_epoch) slot_attestations = [] for validator_index in active_validator_indices: # For each validator, check which committee they belong to (committee, committee_index, committee_slot) = get_committee_assignment(state, validator_epoch, validator_index) # If they belong to a committee attesting for slot s, we ask them to form an attestation # using `honest_attest` defined above. if committee_slot + 1 == state.slot: print("validator attesting", validator_index, "for slot", committee_slot) attestation = honest_attest(state, validator_index) slot_attestations.append(attestation) return ({'slot_attestations': slot_attestations})
def propose_policy(params, step, sL, s): start = time.time() network = s['network'] produced_blocks = [[] for i in range(0, len(network.sets))] attestation_indices = [] for info_set_index, info_set in enumerate(network.sets): if log: print("Looking at info set index =", info_set_index, "time =", time.time() - start) state = info_set.beacon_state current_epoch = specs.get_current_epoch(state) previous_epoch = specs.get_previous_epoch(state) # `validator_epoch` is the epoch of slot s-1. # - If the state is already ahead by one epoch, this is given by `previous_epoch` # - Otherwise it is `current_epoch` if state.slot == specs.compute_start_slot_at_epoch(current_epoch): validator_epoch = previous_epoch else: validator_epoch = current_epoch active_validator_indices = specs.get_active_validator_indices( state, validator_epoch) if log: print("Obtained active validator sets", time.time() - start) proposer_index = specs.get_beacon_proposer_index(state) if proposer_index not in info_set.validators: continue proposer_knowledge = nt.knowledge_set(network, proposer_index) attestations = [ net_item[1].item for net_item in proposer_knowledge["attestations"] ] attestation_indices += [ net_item[0] for net_item in proposer_knowledge["attestations"] ] if log: print("time before aggregation", time.time() - start) attestations = aggregate_attestations(state, attestations) if log: print("time after aggregation", time.time() - start) block = honest_block_proposal(state, attestations, proposer_index) if log: print("time after block proposal", time.time() - start) produced_blocks[info_set_index].append(block) if log: print("time after appending", time.time() - start) if log: print("propose_policy time = ", time.time() - start) return ({ 'blocks': produced_blocks, 'attestation_indices': attestation_indices })
def honest_attest(validator, known_items): # Unpacking validator_index = validator.validator_index store = validator.store committee_slot = validator.data.current_attest_slot committee_index = validator.data.current_committee_index committee = validator.data.current_committee # What am I attesting for? block_root = validator.get_head() head_state = store.block_states[block_root].copy() if head_state.slot < committee_slot: specs.process_slots(head_state, committee_slot) start_slot = specs.compute_start_slot_at_epoch( specs.get_current_epoch(head_state)) epoch_boundary_block_root = block_root if start_slot == head_state.slot else specs.get_block_root_at_slot( head_state, start_slot) tgt_checkpoint = specs.Checkpoint( epoch=specs.get_current_epoch(head_state), root=epoch_boundary_block_root) att_data = specs.AttestationData( index=committee_index, slot=committee_slot, beacon_block_root=block_root, source=head_state.current_justified_checkpoint, target=tgt_checkpoint) # Set aggregation bits to myself only committee_size = len(committee) index_in_committee = committee.index(validator_index) aggregation_bits = Bitlist[specs.MAX_VALIDATORS_PER_COMMITTEE]( *([0] * committee_size)) aggregation_bits[ index_in_committee] = True # set the aggregation bit of the validator to True attestation = specs.Attestation(aggregation_bits=aggregation_bits, data=att_data) # print(validator.validator_index, "attests for slot", committee_slot) return attestation
def attest_policy(params, step, sL, s): start = time.time() network = s['network'] produced_attestations = [[] for i in range(0, len(network.sets))] for info_set_index, info_set in enumerate(network.sets): state = info_set.beacon_state current_epoch = specs.get_current_epoch(state) previous_epoch = specs.get_previous_epoch(state) # `validator_epoch` is the epoch of slot s-1. # - If the state is already ahead by one epoch, this is given by `previous_epoch` # - Otherwise it is `current_epoch` if state.slot == specs.compute_start_slot_at_epoch(current_epoch): validator_epoch = previous_epoch else: validator_epoch = current_epoch active_validator_indices = specs.get_active_validator_indices( state, validator_epoch) number_of_committees = specs.get_committee_count_at_slot( state, state.slot - 1) for committee_index in range(number_of_committees): committee = specs.get_beacon_committee(state, state.slot - 1, committee_index) for validator_index in committee: if validator_index not in info_set.validators: continue attestation = honest_attest(state, validator_index) produced_attestations[info_set_index].append( [validator_index, attestation]) if log: print("--------------") if log: print("attest_policy time = ", time.time() - start) return ({'attestations': produced_attestations})
def honest_attest(state, validator_index): # Given state w-[s+1], validators in committees of slot s form their attestations # In several places here, we need to check whether s+1 is the first slot of a new epoch. current_epoch = get_current_epoch(state) previous_epoch = get_previous_epoch(state) # Since everyone is honest, we can assume that validators attesting during some epoch e # choose the first block of e as their target, and the first block of e-1 as their source checkpoint. # # So let's assume we are making an attestation at slot s in epoch e: # # - If the `state` variable is at epoch e, then the first block of e-1 is a checkpoint held in # `state.current_justified_checkpoint`. The target checkpoint root is obtained by calling # `get_block_root(state, current_epoch)` (since current_epoch = e). # # - If the `state` variable is at epoch e+1, then the first block of e-1 is a checkpoint held in # `state.previous_justified_checkpoint`, since in the meantime the first block of e was justified. This # is the case when s is the last slot of epoch $e$. The target checkpoint root is obtained by calling # `get_block_root(state, previous_epoch)` (since current_epoch = e+1). # # ... still here? if state.slot == compute_start_slot_at_epoch(current_epoch): # `committee_slot` is equal to s (committee, committee_index, committee_slot) = get_committee_assignment(state, previous_epoch, validator_index) # Since we are at state w-[s+1], we can get the block root of the block at slot s. block_root = get_block_root_at_slot(state, committee_slot) src_checkpoint = Checkpoint( epoch=state.previous_justified_checkpoint.epoch, root=state.previous_justified_checkpoint.root) tgt_checkpoint = Checkpoint(epoch=previous_epoch, root=get_block_root(state, previous_epoch)) else: # `committee_slot` is equal to s (committee, committee_index, committee_slot) = get_committee_assignment(state, current_epoch, validator_index) # Since we are at state w-[s+1], we can get the block root of the block at slot s. block_root = get_block_root_at_slot(state, committee_slot) src_checkpoint = Checkpoint( epoch=state.current_justified_checkpoint.epoch, root=state.current_justified_checkpoint.root) tgt_checkpoint = Checkpoint(epoch=current_epoch, root=get_block_root(state, current_epoch)) att_data = AttestationData(index=committee_index, slot=committee_slot, beacon_block_root=block_root, source=src_checkpoint, target=tgt_checkpoint) print("attestation for source", src_checkpoint.epoch, "and target", tgt_checkpoint.epoch) # For now we disregard aggregation of attestations. # Some validators are chosen as aggregators: they take a bunch of identical attestations # and join them together in one object, with `aggregation_bits` identifying which validators # are part of the aggregation. committee_size = len(committee) index_in_committee = committee.index(validator_index) aggregation_bits = Bitlist[MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size)) aggregation_bits[ index_in_committee] = True # set the aggregation bits of the validator to True attestation = Attestation(aggregation_bits=aggregation_bits, data=att_data) return attestation