def get_rewards_for_cycle_map(self, cycle): current_level, current_cycle = self.__get_current_level() logger.debug("Current level {}, current cycle {}".format(current_level, current_cycle)) reward_data = {} reward_data["delegate_staking_balance"], reward_data[ "delegators"] = self.__get_delegators_and_delgators_balances(cycle, current_level) reward_data["delegators_nb"] = len(reward_data["delegators"]) # Get last block in cycle where rewards are unfrozen level_of_last_block_in_unfreeze_cycle = (cycle + self.preserved_cycles + 1) * self.blocks_per_cycle logger.debug("Cycle {}, preserved cycles {}, blocks per cycle {}, last block of cycle {}" .format(cycle, self.preserved_cycles, self.blocks_per_cycle, level_of_last_block_in_unfreeze_cycle)) if current_level - level_of_last_block_in_unfreeze_cycle >= 0: unfrozen_fees, unfrozen_rewards = self.__get_unfrozen_rewards(level_of_last_block_in_unfreeze_cycle, cycle) reward_data["total_rewards"] = unfrozen_fees + unfrozen_rewards else: logger.warn("Please wait until the rewards and fees for cycle {} are unfrozen".format(cycle)) reward_data["total_rewards"] = 0 reward_model = RewardProviderModel(reward_data["delegate_staking_balance"], reward_data["total_rewards"], reward_data["delegators"]) logger.debug("delegate_staking_balance = {}, total_rewards = {}" .format(reward_data["delegate_staking_balance"], reward_data["total_rewards"])) logger.debug("delegators = {}".format(reward_data["delegators"])) return reward_model
def get_rewards_for_cycle_map(self, cycle): root = self.helper.get_rewards_for_cycle(cycle, self.verbose) delegate_staking_balance = int(root["delegate_staking_balance"]) blocks_rewards = int(root["blocks_rewards"]) future_blocks_rewards = int(root["future_blocks_rewards"]) endorsements_rewards = int(root["endorsements_rewards"]) future_endorsements_rewards = int(root["future_endorsements_rewards"]) lost_rewards_denounciation = int( root["lost_rewards_denounciation_baking"]) + int( root["lost_rewards_denounciation_endorsement"]) lost_fees_denounciation = int( root["lost_fees_denounciation_baking"]) + int( root["lost_fees_denounciation_endorsement"]) fees = int(root["fees"]) total_reward_amount = (blocks_rewards + endorsements_rewards + future_blocks_rewards + future_endorsements_rewards + fees - lost_rewards_denounciation - lost_fees_denounciation) delegators_balance = root["delegators_balance"] delegator_balance_dict = {} for dbalance in delegators_balance: address = dbalance[0]["tz"] balance = int(dbalance[1]) delegator_balance_dict[address] = balance return RewardProviderModel(delegate_staking_balance, total_reward_amount, delegator_balance_dict)
def get_rewards_for_cycle_map(self, cycle, verbose=False): reward_data = {} reward_data["delegate_staking_balance"], reward_data[ "delegators"] = self.__get_delegators_and_delgators_balance( cycle, verbose) reward_data["delegators_nb"] = len(reward_data["delegators"]) current_level, head_hash, current_cycle = self.__get_current_level( verbose) logger.debug("Current level {}, head hash {}".format( current_level, head_hash)) # Get last block in cycle where rewards are unfrozen level_for_relevant_request = ( cycle + self.preserved_cycles + 1 - self.cycle_offset) * self.blocks_per_cycle logger.debug( "Cycle {}, preserved cycles {}, blocks per cycle {}, level of interest {}" .format(cycle, self.preserved_cycles, self.blocks_per_cycle, level_for_relevant_request)) if current_level - level_for_relevant_request >= 0: request_metadata = COMM_BLOCK.format( self.node_url, head_hash, current_level - level_for_relevant_request) + '/metadata/' _, response_metadata = self.wllt_clnt_mngr.send_request( request_metadata) metadata = parse_json_response(response_metadata) balance_updates = metadata["balance_updates"] unfrozen_rewards = unfrozen_fees = 0 for i in range(len(balance_updates)): balance_update = balance_updates[i] if balance_update["kind"] == "freezer": if balance_update["delegate"] == self.baking_address: if balance_update["category"] == "rewards": unfrozen_rewards = -int(balance_update["change"]) elif balance_update["category"] == "fees": unfrozen_fees = -int(balance_update["change"]) reward_data["total_rewards"] = unfrozen_rewards + unfrozen_fees else: logger.warn( "Please wait until the rewards and fees for cycle {} are unfrozen" .format(cycle)) reward_data["total_rewards"] = 0 reward_model = RewardProviderModel( reward_data["delegate_staking_balance"], reward_data["total_rewards"], reward_data["delegators"]) if self.validate: self.__validate_reward_data(reward_model, cycle) return reward_model
def get_rewards_for_cycle_map(self, cycle, expected_reward = False): root = self.helper.get_rewards_for_cycle(cycle, expected_reward, self.verbose) delegate_staking_balance = root["delegate_staking_balance"] total_reward_amount = root["total_reward_amount"] delegators_balances_dict = root["delegators_balances"] return RewardProviderModel(delegate_staking_balance, total_reward_amount, delegators_balances_dict)
def get_rewards_for_cycle_map(self, cycle, expected_reward=False): root = self.helper.get_rewards_for_cycle(cycle, expected_reward) delegate_staking_balance = root["delegate_staking_balance"] total_reward_amount = root["total_reward_amount"] delegators_balances_dict = root["delegators_balances"] snapshot_level = self.helper.get_snapshot_level(cycle) for delegator in self.dexter_contracts_set: dxtz.process_original_delegators_map(delegators_balances_dict, delegator, snapshot_level, self.helper) return RewardProviderModel(delegate_staking_balance, total_reward_amount, delegators_balances_dict)
def get_rewards_for_cycle_map(self, cycle): try: current_level, current_cycle = self.__get_current_level() logger.debug("Current level {:d}, current cycle {:d}".format(current_level, current_cycle)) reward_data = {} reward_data["delegate_staking_balance"], reward_data[ "delegators"] = self.__get_delegators_and_delgators_balances(cycle, current_level) reward_data["delegators_nb"] = len(reward_data["delegators"]) # Get last block in cycle where rewards are unfrozen level_of_last_block_in_unfreeze_cycle = (cycle + self.preserved_cycles + 1) * self.blocks_per_cycle logger.debug("Cycle {:d}, preserved cycles {:d}, blocks per cycle {:d}, last block of cycle {:d}" .format(cycle, self.preserved_cycles, self.blocks_per_cycle, level_of_last_block_in_unfreeze_cycle)) if current_level - level_of_last_block_in_unfreeze_cycle >= 0: unfrozen_fees, unfrozen_rewards = self.__get_unfrozen_rewards(level_of_last_block_in_unfreeze_cycle, cycle) reward_data["total_rewards"] = unfrozen_fees + unfrozen_rewards else: logger.warning("Please wait until the rewards and fees for cycle {:d} are unfrozen".format(cycle)) reward_data["total_rewards"] = 0 _, snapshot_level = self.__get_roll_snapshot_block_level(cycle, current_level) for delegator in self.dexter_contracts_set: dxtz.process_original_delegators_map(reward_data["delegators"], delegator, snapshot_level) reward_model = RewardProviderModel(reward_data["delegate_staking_balance"], reward_data["total_rewards"], reward_data["delegators"]) logger.debug("delegate_staking_balance = {:d}, total_rewards = {:d}" .format(reward_data["delegate_staking_balance"], reward_data["total_rewards"])) logger.debug("delegators = {}".format(reward_data["delegators"])) return reward_model except Exception as e: # We should abort here on any exception as we did not fetch all # necessary data to properly compute rewards raise e from e
def get_rewards_for_cycle_map(self, cycle, rewards_type): root = self.helper.get_rewards_for_cycle(cycle) delegate_staking_balance = root["delegate_staking_balance"] num_baking_rights = root["num_baking_rights"] num_endorsing_rights = root["num_endorsing_rights"] delegators_balances_dict = root["delegators_balances"] rewards_and_fees = root["rewards_and_fees"] equivocation_losses = root["equivocation_losses"] denunciation_rewards = root["denunciation_rewards"] total_reward_amount = ( rewards_and_fees - equivocation_losses + denunciation_rewards ) offline_losses = root["offline_losses"] snapshot_level = self.helper.get_snapshot_level(cycle) for delegator in self.dexter_contracts_set: if delegator in delegators_balances_dict: dxtz.process_original_delegators_map( delegators_balances_dict, delegator, snapshot_level, self.helper ) else: logger.warning( f"The configured Dexter account {delegator} is not delegated to {self.helper.baking_address} " f"at snapshot level {snapshot_level} corresponding to payout cycle {cycle} or has a zero rewards" ) return RewardProviderModel( delegate_staking_balance, num_baking_rights, num_endorsing_rights, total_reward_amount, rewards_and_fees, equivocation_losses, denunciation_rewards, offline_losses, delegators_balances_dict, None, )
def get_rewards_for_cycle_map(self, cycle, expected_reward=False): root = self.helper.get_rewards_for_cycle(cycle, expected_reward) delegate_staking_balance = root["delegate_staking_balance"] total_reward_amount = root["total_reward_amount"] delegators_balances_dict = root["delegators_balances"] snapshot_level = self.helper.get_snapshot_level(cycle) for delegator in self.dexter_contracts_set: if delegator in delegators_balances_dict: dxtz.process_original_delegators_map(delegators_balances_dict, delegator, snapshot_level, self.helper) else: logger.warning( f"The configured Dexter account {delegator} is not delegated to {self.helper.baking_address} " f"at snapshot level {snapshot_level} corresponding to payout cycle {cycle} or has a zero rewards" ) return RewardProviderModel(delegate_staking_balance, total_reward_amount, delegators_balances_dict)
def get_rewards_for_cycle_map(self, cycle, rewards_type) -> RewardProviderModel: """ Returns reward split in a specified format :param cycle: :return: RewardProviderModel( delegate_staking_balance=5265698993303, num_blocks=333, num_endorsements=3333, delegators_balances={ 'tz1azSbB91MbdcEquhsmJvjVroLs5t4kpdCn': { 'staking_balance': 1935059821, 'current_balance': 1977503559 } } ) """ split = self.api.get_reward_split(address=self.baking_address, cycle=cycle, fetch_delegators=True) delegate_staking_balance = split["stakingBalance"] # calculate estimated rewards num_blocks = (split["ownBlocks"] + split["missedOwnBlocks"] + split["uncoveredOwnBlocks"] + split["futureBlocks"]) num_endorsements = (split["endorsements"] + split["missedEndorsements"] + split["uncoveredEndorsements"] + split["futureEndorsements"]) # rewards earned (excluding equivocation losses) rewards_and_fees = (split["ownBlockRewards"] + split["extraBlockRewards"] + split["endorsementRewards"] + split["ownBlockFees"] + split["extraBlockFees"] + split["revelationRewards"]) denunciation_rewards = (split["doubleBakingRewards"] + split["doubleEndorsingRewards"]) equivocation_losses = (split["doubleBakingLostDeposits"] + split["doubleBakingLostRewards"] + split["doubleBakingLostFees"] + split["doubleEndorsingLostDeposits"] + split["doubleEndorsingLostRewards"] + split["doubleEndorsingLostFees"] + split["revelationLostRewards"] + split["revelationLostFees"]) total_reward_amount = max( 0, rewards_and_fees + denunciation_rewards - equivocation_losses) # losses due to being offline or not having enough bond offline_losses = ( split["missedOwnBlockRewards"] + split["missedExtraBlockRewards"] + split["uncoveredOwnBlockRewards"] + split["uncoveredExtraBlockRewards"] + split["missedEndorsementRewards"] + split["uncoveredEndorsementRewards"] + split["missedOwnBlockFees"] + split["missedExtraBlockFees"] + split["uncoveredOwnBlockFees"] + split["uncoveredExtraBlockFees"]) delegators_balances = { item["address"]: { "staking_balance": item["balance"], "current_balance": item["currentBalance"], } for item in split["delegators"] if item["balance"] > 0 } # TODO: support Dexter for TzKt # snapshot_level = self.api.get_snapshot_level(cycle) # for delegator in self.dexter_contracts_set: # dxtz.process_original_delegators_map(delegators_balances, delegator, snapshot_level) return RewardProviderModel( delegate_staking_balance, num_blocks, num_endorsements, total_reward_amount, rewards_and_fees, equivocation_losses, denunciation_rewards, offline_losses, delegators_balances, None, )
def get_rewards_for_cycle_map(self, cycle, expected_reward=False ) -> RewardProviderModel: """ Returns reward split in a specified format :param cycle: :param expected_reward: :return: RewardProviderModel( delegate_staking_balance=5265698993303, total_reward_amount=2790471275, delegators_balances={ 'tz1azSbB91MbdcEquhsmJvjVroLs5t4kpdCn': { 'staking_balance': 1935059821, 'current_balance': 1977503559 } } ) """ split = self.api.get_reward_split(address=self.baking_address, cycle=cycle, fetch_delegators=True) delegate_staking_balance = split['stakingBalance'] if expected_reward: num_blocks = \ split['ownBlocks'] \ + split['missedOwnBlocks'] \ + split['uncoveredOwnBlocks'] \ + split['futureBlocks'] num_endorsements = \ split['endorsements'] \ + split['missedEndorsements'] \ + split['uncoveredEndorsements'] \ + split['futureEndorsements'] total_reward_amount = self.calc_expected_reward( cycle, num_blocks, num_endorsements) else: total_reward_amount = \ split['ownBlockRewards'] \ + split['extraBlockRewards'] \ + split['endorsementRewards'] \ + split['ownBlockFees'] \ + split['extraBlockFees'] \ + split['revelationRewards'] \ + split['doubleBakingRewards'] \ + split['doubleEndorsingRewards'] \ - split['doubleBakingLostDeposits'] \ - split['doubleBakingLostRewards'] \ - split['doubleBakingLostFees'] \ - split['doubleEndorsingLostDeposits'] \ - split['doubleEndorsingLostRewards'] \ - split['doubleEndorsingLostFees'] \ - split['revelationLostRewards'] \ - split['revelationLostFees'] total_reward_amount = max(0, total_reward_amount) delegators_balances = { item['address']: { 'staking_balance': item['balance'], 'current_balance': item['currentBalance'] } for item in split['delegators'] if item['balance'] > 0 } # TODO: support Dexter for TzKt # snapshot_level = self.api.get_snapshot_level(cycle) # for delegator in self.dexter_contracts_set: # dxtz.process_original_delegators_map(delegators_balances, delegator, snapshot_level) return RewardProviderModel(delegate_staking_balance, total_reward_amount, delegators_balances)
def get_rewards_for_cycle_map(self, cycle, rewards_type): try: current_level, current_cycle = self.__get_current_level() logger.debug( "Current level {:d}, current cycle {:d}".format( current_level, current_cycle ) ) reward_data = {} ( reward_data["delegate_staking_balance"], reward_data["delegators"], ) = self.__get_delegators_and_delgators_balances(cycle, current_level) reward_data["delegators_nb"] = len(reward_data["delegators"]) # Get last block in cycle where rewards are unfrozen if cycle >= FIRST_CYCLE_REWARDS_GRANADA: # Since cycle 394, we use an offset of 1589248 blocks (388 cycles pre-Granada of 4096 blocks each) # Cycles start at 0 level_of_last_block_in_unfreeze_cycle = BLOCKS_BEFORE_GRANADA + ( (cycle - CYCLES_BEFORE_GRANADA + self.preserved_cycles + 1) * self.blocks_per_cycle ) level_of_first_block_in_preserved_cycles = BLOCKS_BEFORE_GRANADA + ( (cycle - CYCLES_BEFORE_GRANADA - self.preserved_cycles) * self.blocks_per_cycle + 1 ) else: # Using pre-Granada calculation level_of_last_block_in_unfreeze_cycle = ( cycle + self.preserved_cycles + 1 ) * BLOCKS_PER_CYCLE_BEFORE_GRANADA level_of_first_block_in_preserved_cycles = ( cycle - self.preserved_cycles ) * BLOCKS_PER_CYCLE_BEFORE_GRANADA + 1 logger.debug( "Cycle {:d}, preserved cycles {:d}, blocks per cycle {:d}, last block of cycle {:d}, " "last block unfreeze cycle {:d}".format( cycle, self.preserved_cycles, self.blocks_per_cycle, level_of_first_block_in_preserved_cycles, level_of_last_block_in_unfreeze_cycle, ) ) # Determine how many priority 0 baking rights delegate had baking_rights = self.__get_baking_rights( cycle, level_of_first_block_in_preserved_cycles ) endorsement_rights = self.__get_endorsement_rights( cycle, level_of_first_block_in_preserved_cycles ) nb_blocks = len([r for r in baking_rights if r["priority"] == 0]) nb_endorsements = sum([len(r["slots"]) for r in endorsement_rights]) total_reward_amount = None if not rewards_type.isEstimated(): # Calculate actual rewards if current_level - level_of_last_block_in_unfreeze_cycle >= 0: unfrozen_fees, unfrozen_rewards = self.__get_unfrozen_rewards( level_of_last_block_in_unfreeze_cycle, cycle ) total_reward_amount = unfrozen_fees + unfrozen_rewards else: frozen_fees, frozen_rewards = self.__get_frozen_rewards( cycle, current_level ) total_reward_amount = frozen_fees + frozen_rewards # Without an indexer, it is not possible to itemize rewards # so setting these values below to "None" rewards_and_fees = None equivocation_losses = None denunciation_rewards = None offline_losses = None if rewards_type.isIdeal(): # Calculate offline losses missed_baking_income = 0 for count, r in enumerate(baking_rights): if count % 10 == 0: logger.info( "Verifying bake ({}/{}).".format(count, len(baking_rights)) ) if r["priority"] == 0: if self.__get_block_author(r["level"]) != self.baking_address: logger.warning( "Found missed baking slot {}, adding {:<,d} mutez reward anyway.".format( r, self.block_reward ) ) missed_baking_income += self.block_reward missed_endorsing_income = 0 for count, r in enumerate(endorsement_rights): if count % 10 == 0: logger.info( "Verifying endorsement ({}/{}).".format( count, len(endorsement_rights) ) ) authored_endorsement_slots = ( self.__get_authored_endorsement_slots_by_level(r["level"] + 1) ) if authored_endorsement_slots != r["slots"]: mutez_to_add = self.endorsement_reward * len(r["slots"]) logger.warning( "Found {} missed endorsement(s) at level {}, adding {:<,d} mutez reward anyway.".format( len(r["slots"]), r["level"], mutez_to_add ) ) missed_endorsing_income += mutez_to_add offline_losses = missed_baking_income + missed_endorsing_income # TODO: support Dexter for RPC # _, snapshot_level = self.__get_roll_snapshot_block_level(cycle, current_level) # for delegator in self.dexter_contracts_set: # dxtz.process_original_delegators_map(reward_data["delegators"], delegator, snapshot_level) reward_model = RewardProviderModel( reward_data["delegate_staking_balance"], nb_blocks, nb_endorsements, total_reward_amount, rewards_and_fees, equivocation_losses, denunciation_rewards, offline_losses, reward_data["delegators"], None, ) logger.debug( "delegate_staking_balance = {:d}".format( reward_data["delegate_staking_balance"] ) ) logger.debug("delegators = {}".format(reward_data["delegators"])) return reward_model except Exception as e: # We should abort here on any exception as we did not fetch all # necessary data to properly compute rewards raise e from e
def get_rewards_for_cycle_map(self, cycle, expected_rewards=False): try: current_level, current_cycle = self.__get_current_level() logger.debug("Current level {:d}, current cycle {:d}".format(current_level, current_cycle)) reward_data = {} reward_data["delegate_staking_balance"], reward_data[ "delegators"] = self.__get_delegators_and_delgators_balances(cycle, current_level) reward_data["delegators_nb"] = len(reward_data["delegators"]) # Get last block in cycle where rewards are unfrozen level_of_last_block_in_unfreeze_cycle = (cycle + self.preserved_cycles + 1) * self.blocks_per_cycle level_of_first_block_in_preserved_cycles = (cycle - self.preserved_cycles) * self.blocks_per_cycle + 1 logger.debug("Cycle {:d}, preserved cycles {:d}, blocks per cycle {:d}, last block of cycle {:d}, " "last block unfreeze cycle {:d}" .format(cycle, self.preserved_cycles, self.blocks_per_cycle, level_of_first_block_in_preserved_cycles, level_of_last_block_in_unfreeze_cycle)) # Decide on if paying actual rewards earned, or paying expected/ideal rewards if expected_rewards: # Determine how many priority 0 baking rights delegate had nb_blocks = self.__get_number_of_baking_rights(cycle, level_of_first_block_in_preserved_cycles) nb_endorsements = self.__get_number_of_endorsement_rights(cycle, level_of_first_block_in_preserved_cycles) logger.debug("Number of 0 priority blocks: {}, Number of endorsements: {}".format(nb_blocks, nb_endorsements)) logger.debug("Block reward: {}, Endorsement Reward: {}".format(self.block_reward, self.endorsement_reward)) # "ideally", the baker baked every priority 0 block they had rights for, # and every block they baked contained 32 endorsements total_block_reward = nb_blocks * self.block_reward total_endorsement_reward = nb_endorsements * self.endorsement_reward logger.info("Ideal rewards for cycle {:d}, {:,} block rewards ({:d} blocks), {:,} endorsing rewards ({:d} slots)".format( cycle, total_block_reward, nb_blocks, total_endorsement_reward, nb_endorsements)) reward_data["total_rewards"] = total_block_reward + total_endorsement_reward # Calculate actual rewards else: if current_level - level_of_last_block_in_unfreeze_cycle >= 0: unfrozen_fees, unfrozen_rewards = self.__get_unfrozen_rewards(level_of_last_block_in_unfreeze_cycle, cycle) reward_data["total_rewards"] = unfrozen_fees + unfrozen_rewards else: logger.warning("Please wait until the rewards and fees for cycle {:d} are unfrozen".format(cycle)) reward_data["total_rewards"] = 0 # TODO: support Dexter for RPC # _, snapshot_level = self.__get_roll_snapshot_block_level(cycle, current_level) # for delegator in self.dexter_contracts_set: # dxtz.process_original_delegators_map(reward_data["delegators"], delegator, snapshot_level) reward_model = RewardProviderModel(reward_data["delegate_staking_balance"], reward_data["total_rewards"], reward_data["delegators"]) logger.debug("delegate_staking_balance = {:d}, total_rewards = {:d}" .format(reward_data["delegate_staking_balance"], reward_data["total_rewards"])) logger.debug("delegators = {}".format(reward_data["delegators"])) return reward_model except Exception as e: # We should abort here on any exception as we did not fetch all # necessary data to properly compute rewards raise e from e