def fill_recent_block_hashes(active_state: ActiveState, parent_block: 'Block', block: 'Block') -> ActiveState: return ActiveState( pending_attestations=deepcopy(active_state.pending_attestations), recent_block_hashes=get_new_recent_block_hashes( active_state.recent_block_hashes, parent_block.slot_number, block.slot_number, block.parent_hash), block_vote_cache=deepcopy(active_state.block_vote_cache))
def apply_rewards_and_penalties( crystallized_state: CrystallizedState, active_state: ActiveState, block: 'Block', config: Dict[str, Any] = DEFAULT_CONFIG) -> List['ValidatorRecord']: # FFG Rewards ffg_rewards = calculate_ffg_rewards(crystallized_state, active_state, block, config=config) # Crosslink Rewards crosslink_rewards = calculate_crosslink_rewards(crystallized_state, active_state, block, config=config) updated_validators = deepcopy(crystallized_state.validators) active_validator_indices = get_active_validator_indices( crystallized_state.current_dynasty, crystallized_state.validators) # apply rewards and penalties for index in active_validator_indices: updated_validators[index].balance += (ffg_rewards[index] + crosslink_rewards[index]) # TODO: Keep the balance nonnegative now until we have clear rule of forced exit. if updated_validators[index].balance < 0: updated_validators[index].balance = 0 return updated_validators
def process_block(crystallized_state: CrystallizedState, active_state: ActiveState, block: 'Block', parent_block: 'Block', config: dict = DEFAULT_CONFIG) -> ActiveState: new_block_vote_cache = deepcopy(active_state.block_vote_cache) validate_parent_block_proposer(block, parent_block, crystallized_state, config=config) for attestation in block.attestations: validate_attestation(crystallized_state, active_state, attestation, block, parent_block, config) new_block_vote_cache = get_updated_block_vote_cache( crystallized_state, active_state, attestation, block, new_block_vote_cache, config) new_attestations = active_state.pending_attestations + block.attestations new_chain = Chain(head=block, blocks=active_state.chain.blocks + [block]) new_active_state = ActiveState( pending_attestations=new_attestations, recent_block_hashes=active_state.recent_block_hashes[:], block_vote_cache=new_block_vote_cache, chain=new_chain) return new_active_state
def get_updated_block_vote_cache( crystallized_state: CrystallizedState, active_state: ActiveState, attestation: 'AttestationRecord', block: 'Block', block_vote_cache: BlockVoteCache, config: Dict[str, Any] = DEFAULT_CONFIG) -> BlockVoteCache: new_block_vote_cache = deepcopy(block_vote_cache) parent_hashes = get_signed_parent_hashes(active_state, block, attestation, config) attestation_indices = get_attestation_indices(crystallized_state, attestation, config) for parent_hash in parent_hashes: if parent_hash in attestation.oblique_parent_hashes: continue if parent_hash not in new_block_vote_cache: new_block_vote_cache[parent_hash] = { 'voter_indices': set(), 'total_voter_deposits': 0 } for i, index in enumerate(attestation_indices): if (has_voted(attestation.attester_bitfield, i) and index not in new_block_vote_cache[parent_hash]['voter_indices']): new_block_vote_cache[parent_hash]['voter_indices'].add(index) new_block_vote_cache[parent_hash]['total_voter_deposits'] += ( crystallized_state.validators[index].balance) return new_block_vote_cache
def process_block(crystallized_state: CrystallizedState, active_state: ActiveState, block: 'Block', config: dict = DEFAULT_CONFIG) -> ActiveState: new_block_vote_cache = deepcopy(active_state.block_vote_cache) for attestation in block.attestations: validate_attestation(crystallized_state, active_state, attestation, block, config) new_block_vote_cache = get_updated_block_vote_cache( crystallized_state, active_state, attestation, block, new_block_vote_cache, config) new_attestations = active_state.pending_attestations + block.attestations new_active_state = ActiveState( pending_attestations=new_attestations, recent_block_hashes=active_state.recent_block_hashes[:], block_vote_cache=new_block_vote_cache) return new_active_state
def process_updated_crosslinks( crystallized_state: CrystallizedState, active_state: ActiveState, block: 'Block', config: Dict[str, Any] = DEFAULT_CONFIG) -> List[CrosslinkRecord]: total_attestation_balance = {} # type: Dict[Tuple[ShardId, Hash32], int] crosslinks = deepcopy(crystallized_state.crosslink_records) for attestation in active_state.pending_attestations: shard_tuple = (attestation.shard_id, attestation.shard_block_hash) if shard_tuple not in total_attestation_balance: total_attestation_balance[shard_tuple] = 0 attestation_indices = get_attestation_indices(crystallized_state, attestation, config) # find total committee size by balance total_committee_balance = sum([ crystallized_state.validators[index].balance for index in attestation_indices ]) # find votes cast in attestation by balance total_attestation_balance[shard_tuple] += sum([ crystallized_state.validators[index].balance for in_cycle_slot_height, index in enumerate(attestation_indices) if has_voted(attestation.attester_bitfield, in_cycle_slot_height) ]) # if 2/3 of committee voted on crosslink and do no yet have crosslink # for this shard, for this dynasty, add updated crosslink if (3 * total_attestation_balance[shard_tuple] >= 2 * total_committee_balance and crystallized_state.current_dynasty > crosslinks[attestation.shard_id].dynasty): crosslinks[attestation.shard_id] = CrosslinkRecord( dynasty=crystallized_state.current_dynasty, slot=crystallized_state.last_state_recalc + config['cycle_length'], hash=attestation.shard_block_hash) return crosslinks
def compute_dynasty_transition( crystallized_state: CrystallizedState, block: 'Block', config: Dict[str, Any] = DEFAULT_CONFIG) -> CrystallizedState: crystallized_state = deepcopy(crystallized_state) crystallized_state.current_dynasty += 1 # Not current in spec, but should be added soon crystallized_state.dynasty_start = crystallized_state.last_state_recalc next_start_shard = ( (crystallized_state.shard_and_committee_for_slots[-1][-1].shard_id + 1) % config['shard_count']) crystallized_state.shard_and_committee_for_slots[ config['cycle_length']:] = get_new_shuffling( block.parent_hash, # stub until better RNG crystallized_state.validators, crystallized_state.current_dynasty, next_start_shard) return crystallized_state
def initialize_new_cycle( crystallized_state: CrystallizedState, active_state: ActiveState, block: 'Block', config: Dict[str, Any] = DEFAULT_CONFIG ) -> Tuple[CrystallizedState, ActiveState]: cycle_length = config['cycle_length'] last_state_recalc = crystallized_state.last_state_recalc last_justified_slot = crystallized_state.last_justified_slot last_finalized_slot = crystallized_state.last_finalized_slot justified_streak = crystallized_state.justified_streak total_deposits = crystallized_state.total_deposits # walk through slots last_state_recalc - CYCLE_LENGTH ... last_state_recalc - 1 # and check for justification, streaks, and finality for i in range(cycle_length): slot = i + (last_state_recalc - cycle_length) block_hash = active_state.recent_block_hashes[i] if block_hash in active_state.block_vote_cache: vote_balance = active_state.block_vote_cache[block_hash][ 'total_voter_deposits'] else: vote_balance = 0 if 3 * vote_balance >= 2 * total_deposits: last_justified_slot = max(last_justified_slot, slot) justified_streak += 1 else: justified_streak = 0 if justified_streak >= cycle_length + 1: last_finalized_slot = max(last_finalized_slot, slot - cycle_length - 1) crosslink_records = process_updated_crosslinks(crystallized_state, active_state, block, config) # remove attestations older than last_state_recalc pending_attestations = [ a for a in active_state.pending_attestations if a.slot >= last_state_recalc ] validators = apply_rewards_and_penalties(crystallized_state, active_state, block, config=config) shard_and_committee_for_slots = ( crystallized_state.shard_and_committee_for_slots[cycle_length:] + # this is a stub and will be addressed by shuffling at dynasty change crystallized_state.shard_and_committee_for_slots[cycle_length:]) new_crystallized_state = CrystallizedState( validators=validators, last_state_recalc=last_state_recalc + cycle_length, shard_and_committee_for_slots=shard_and_committee_for_slots, last_justified_slot=last_justified_slot, justified_streak=justified_streak, last_finalized_slot=last_finalized_slot, current_dynasty=crystallized_state.current_dynasty, crosslink_records=crosslink_records, dynasty_seed=crystallized_state.dynasty_seed, dynasty_start=crystallized_state.dynasty_start) new_active_state = ActiveState( pending_attestations=pending_attestations, recent_block_hashes=active_state.recent_block_hashes[:], # Should probably clean up block_vote_cache but old records won't break cache # so okay for now block_vote_cache=deepcopy(active_state.block_vote_cache), chain=deepcopy(active_state.chain), ) return new_crystallized_state, new_active_state