def try_to_pay(self, pymnt_cycle): try: logger.info("Payment cycle is " + str(pymnt_cycle)) # 0- check for past payment evidence for current cycle past_payment_state = check_past_payment(self.payments_root, pymnt_cycle) if not self.dry_run and past_payment_state: logger.warn(past_payment_state) return True # 1- get reward data reward_model = self.reward_api.get_rewards_for_cycle_map(pymnt_cycle) # 2- calculate rewards reward_logs, total_amount = self.payment_calc.calculate(reward_model) # set cycle info for rl in reward_logs: rl.cycle = pymnt_cycle total_amount_to_pay = sum([rl.amount for rl in reward_logs if rl.payable]) # 4- if total_rewards > 0, proceed with payment if total_amount_to_pay > 0: report_file_path = get_calculation_report_file(self.calculations_dir, pymnt_cycle) # 5- send to payment consumer self.payments_queue.put(PaymentBatch(self, pymnt_cycle, reward_logs)) # logger.info("Total payment amount is {:,} mutez. %s".format(total_amount_to_pay), # "" if self.delegator_pays_xfer_fee else "(Transfer fee is not included)") logger.debug("Creating calculation report (%s)", report_file_path) # 6- create calculations report file. This file contains calculations details self.create_calculations_report(reward_logs, report_file_path, total_amount) # 7- next cycle # processing of cycle is done logger.info( "Reward creation is done for cycle {}, created {} rewards.".format(pymnt_cycle, len(reward_logs))) elif total_amount_to_pay == 0: logger.info("Total payment amount is 0. Nothing to pay!") return True except ReadTimeout: logger.info("Tzscan call failed, will try again.") logger.debug("Tzscan call failed", exc_info=False) return False except ConnectTimeout: logger.info("Tzscan connection failed, will try again.") logger.debug("Tzscan connection failed", exc_info=False) return False except TzScanException: logger.info("Tzscan error at reward loop, will try again.") logger.debug("Tzscan error at reward loop", exc_info=False) return False except Exception: logger.error("Error at payment producer loop, will try again.", exc_info=True) return False finally: sleep(10)
def try_to_pay(self, payment_cycle): try: logger.info("Payment cycle is " + str(payment_cycle)) # 1- get reward data reward_data = self.reward_api.get_rewards_for_cycle_map( payment_cycle, verbose=self.verbose) # 2- make payment calculations from reward data pymnt_logs, total_rewards = self.make_payment_calculations( payment_cycle, reward_data) # 3- check for past payment evidence for current cycle past_payment_state = check_past_payment(self.payments_root, payment_cycle) if not self.dry_run and total_rewards > 0 and past_payment_state: logger.warn(past_payment_state) total_rewards = 0 # 4- if total_rewards > 0, proceed with payment if total_rewards > 0: report_file_path = get_calculation_report_file( self.calculations_dir, payment_cycle) # 5- send to payment consumer self.payments_queue.put(pymnt_logs) # 6- create calculations report file. This file contains calculations details self.create_calculations_report(payment_cycle, pymnt_logs, report_file_path, total_rewards) # processing of cycle is done logger.info("Reward creation done for cycle %s", payment_cycle) return True except TzScanException: logger.warn("Tzscan error at reward calculation", exc_info=True) return False except Exception: logger.error("Error at reward calculation", exc_info=True) return False
def try_to_pay(self, pymnt_cycle, expected_rewards=False): try: logger.info("Payment cycle is " + str(pymnt_cycle)) # 0- check for past payment evidence for current cycle past_payment_state = check_past_payment(self.payments_root, pymnt_cycle) if not self.dry_run and past_payment_state: logger.warn(past_payment_state) return True # 1- get reward data if expected_rewards: logger.info( "Using expected/ideal rewards for payouts calculations") else: logger.info("Using actual rewards for payouts calculations") reward_model = self.reward_api.get_rewards_for_cycle_map( pymnt_cycle, expected_rewards) # 2- calculate rewards reward_logs, total_amount = self.payment_calc.calculate( reward_model) # 3- set cycle info for rl in reward_logs: rl.cycle = pymnt_cycle total_amount_to_pay = sum( [rl.amount for rl in reward_logs if rl.payable]) # 4- if total_rewards > 0, proceed with payment if total_amount_to_pay > 0: report_file_path = get_calculation_report_file( self.calculations_dir, pymnt_cycle) # 5- send to payment consumer self.payments_queue.put( PaymentBatch(self, pymnt_cycle, reward_logs)) # logger.info("Total payment amount is {:,} mutez. %s".format(total_amount_to_pay), # "" if self.delegator_pays_xfer_fee else "(Transfer fee is not included)") logger.debug("Creating calculation report (%s)", report_file_path) sleep(5.0) # 6- create calculations report file. This file contains calculations details self.create_calculations_report(reward_logs, report_file_path, total_amount, expected_rewards) # 7- processing of cycle is done logger.info( "Reward creation is done for cycle {}, created {} rewards." .format(pymnt_cycle, len(reward_logs))) elif total_amount_to_pay == 0: logger.info("Total payment amount is 0. Nothing to pay!") except ApiProviderException as a: logger.error("[try_to_pay] API provider error {:s}".format(str(a))) raise a from a except Exception as e: logger.error("[try_to_pay] Generic exception {:s}".format(str(e))) raise e from e # Either succeeded or raised exception return True
def try_to_pay(self, pymnt_cycle, rewards_type, network_config): try: logger.info("Payment cycle is {:s}".format(str(pymnt_cycle))) # 0- check for past payment evidence for current cycle past_payment_state = check_past_payment(self.payments_root, pymnt_cycle) if past_payment_state: logger.warn(past_payment_state) return True # 1- get reward data reward_model = self.reward_api.get_rewards_for_cycle_map( pymnt_cycle, rewards_type) # 2- compute reward amount to distribute based on configuration reward_model.computed_reward_amount = self.compute_rewards( reward_model, rewards_type, network_config) # 3- calculate rewards for delegators reward_logs, total_amount = self.payment_calc.calculate( reward_model) # 4- set cycle info for rl in reward_logs: rl.cycle = pymnt_cycle total_amount_to_pay = sum( [rl.amount for rl in reward_logs if rl.payable]) # 5- if total_rewards > 0, proceed with payment if total_amount_to_pay > 0: # 6- send to payment consumer self.payments_queue.put( PaymentBatch(self, pymnt_cycle, reward_logs)) sleep(5.0) # 7- create calculations report file. This file contains calculations details report_file_path = get_calculation_report_file( self.calculations_dir, pymnt_cycle) logger.debug("Creating calculation report (%s)", report_file_path) self.create_calculations_report(reward_logs, report_file_path, total_amount, rewards_type) # 8- processing of cycle is done logger.info( "Reward creation is done for cycle {}, created {} rewards." .format(pymnt_cycle, len(reward_logs))) elif total_amount_to_pay == 0: logger.info("Total payment amount is 0. Nothing to pay!") except ApiProviderException as a: logger.error("[try_to_pay] API provider error {:s}".format(str(a))) raise a from a except Exception as e: logger.error("[try_to_pay] Generic exception {:s}".format(str(e))) raise e from e # Either succeeded or raised exception return True
def run(self): current_cycle = self.block_api.get_current_cycle() payment_cycle = self.initial_payment_cycle # if non-positive initial_payment_cycle, set initial_payment_cycle to # 'current cycle - abs(initial_cycle) - (NB_FREEZE_CYCLE+1)' if self.initial_payment_cycle <= 0: payment_cycle = current_cycle - abs(self.initial_payment_cycle) - ( self.nw_config['NB_FREEZE_CYCLE'] + 1) logger.debug("Payment cycle is set to {}".format(payment_cycle)) while self.life_cycle.is_running(): # take a breath time.sleep(5) logger.debug("Trying payments for cycle {}".format(payment_cycle)) current_level = self.block_api.get_current_level() current_cycle = self.block_api.level_to_cycle(current_level) # create reports dir if self.calculations_dir and not os.path.exists( self.calculations_dir): os.makedirs(self.calculations_dir) logger.debug( "Checking for pending payments : payment_cycle <= " "current_cycle - (self.nw_config['NB_FREEZE_CYCLE'] + 1) - self.release_override" ) logger.debug( "Checking for pending payments : checking {} <= {} - ({} + 1) - {}" .format(payment_cycle, current_cycle, self.nw_config['NB_FREEZE_CYCLE'], self.release_override)) # payments should not pass beyond last released reward cycle if payment_cycle <= current_cycle - ( self.nw_config['NB_FREEZE_CYCLE'] + 1) - self.release_override: if not self.payments_queue.full(): try: logger.info("Payment cycle is " + str(payment_cycle)) # 1- get reward data reward_data = self.reward_api.get_rewards_for_cycle_map( payment_cycle, verbose=self.verbose) # 2- make payment calculations from reward data pymnt_logs, total_rewards = self.make_payment_calculations( payment_cycle, reward_data) # 3- check for past payment evidence for current cycle past_payment_state = check_past_payment( self.payments_root, payment_cycle) if not self.dry_run and total_rewards > 0 and past_payment_state: logger.warn(past_payment_state) total_rewards = 0 # 4- if total_rewards > 0, proceed with payment if total_rewards > 0: report_file_path = get_calculation_report_file( self.calculations_dir, payment_cycle) # 5- send to payment consumer self.payments_queue.put(pymnt_logs) # 6- create calculations report file. This file contains calculations details self.create_calculations_report( payment_cycle, pymnt_logs, report_file_path, total_rewards) # 7- next cycle # processing of cycle is done logger.info("Reward creation done for cycle %s", payment_cycle) payment_cycle = payment_cycle + 1 # single run is done. Do not continue. if self.run_mode == RunMode.ONETIME: logger.info( "Run mode ONETIME satisfied. Killing the thread ..." ) self.exit() break except Exception: logger.error("Error at reward calculation", exc_info=True) # end of queue size check else: logger.debug("Wait a few minutes, queue is full") # wait a few minutes to let payments done time.sleep(60 * 3) # end of payment cycle check else: logger.debug( "No pending payments for cycle {}, current cycle is {}". format(payment_cycle, current_cycle)) # pending payments done. Do not wait any more. if self.run_mode == RunMode.PENDING: logger.info( "Run mode PENDING satisfied. Killing the thread ...") self.exit() break time.sleep(10) self.retry_failed_payments() # calculate number of blocks until end of current cycle nb_blocks_remaining = ( current_cycle + 1) * self.nw_config['BLOCKS_PER_CYCLE'] - current_level # plus offset. cycle beginnings may be busy, move payments forward nb_blocks_remaining = nb_blocks_remaining + self.payment_offset logger.debug("Wait until next cycle, for {} blocks".format( nb_blocks_remaining)) # wait until current cycle ends self.waint_until_next_cycle(nb_blocks_remaining) # end of endless loop logger.info("Producer returning ...") # ensure consumer exits self.exit() return
def try_to_pay(self, pymnt_cycle, rewards_type, network_config, current_cycle): try: logger.info("Payment cycle is {:s}".format(str(pymnt_cycle))) # 0- check for past payment evidence for current cycle past_payment_state = check_past_payment(self.payments_root, pymnt_cycle) if past_payment_state: logger.warn(past_payment_state) return True adjustments = {} early_payout = False current_cycle_rewards_type = rewards_type # 1- adjust past cycle if necessary if self.release_override == -11 and pymnt_cycle >= current_cycle: early_payout = True completed_cycle = pymnt_cycle - 6 adjustments = self.recompute_rewards(completed_cycle, rewards_type, network_config) # payout for current cycle will be estimated since we don't know actual rewards yet current_cycle_rewards_type = RewardsType.ESTIMATED # 2- get reward data and compute how to distribute them reward_logs, total_amount = self.compute_rewards( pymnt_cycle, current_cycle_rewards_type, network_config, adjustments) total_recovered_adjustments = int( sum([rl.adjustment for rl in reward_logs])) total_adjustments_to_recover = int(sum(adjustments.values())) if total_adjustments_to_recover > 0: logger.debug( "Total adjustments to recover is {:<,d} mutez, total recovered adjustment is {:<,d} mutez." .format(total_adjustments_to_recover, total_recovered_adjustments)) logger.info( "After early payout of cycle {:s}, {:<,d} mutez were not recovered." .format( str(completed_cycle), total_adjustments_to_recover + total_recovered_adjustments, )) # 3- create calculations report file. This file contains calculations details report_file_path = get_calculation_report_file_path( self.calculations_dir, pymnt_cycle) logger.debug("Creating calculation report (%s)", report_file_path) CsvCalculationFileParser().write( reward_logs, report_file_path, total_amount, current_cycle_rewards_type, self.baking_address, early_payout, ) # 4- set cycle info for reward_log in reward_logs: reward_log.cycle = pymnt_cycle total_amount_to_pay = int( sum([ reward_log.adjusted_amount for reward_log in reward_logs if reward_log.payable ])) # 5- if total_rewards > 0, proceed with payment if total_amount_to_pay > 0: self.payments_queue.put( PaymentBatch(self, pymnt_cycle, reward_logs)) sleep(5.0) # 6- processing of cycle is done logger.info( "Reward creation is done for cycle {}, created {} rewards." .format(pymnt_cycle, len(reward_logs))) elif total_amount_to_pay == 0: logger.info("Total payment amount is 0. Nothing to pay!") except ApiProviderException as a: logger.error("[try_to_pay] API provider error {:s}".format(str(a))) raise a from a except Exception as e: logger.error("[try_to_pay] Generic exception {:s}".format(str(e))) raise e from e # Either succeeded or raised exception return True