예제 #1
0
def main():
    global CONFIG
    global LOGGER
    CONFIG = lib.get_config()
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))

    # Number of blocks of share data used to calculate rewards
    PPLNG_WINDOW_SIZE = 60
    try:
        PPLNG_WINDOW_SIZE = int(os.environ["PPLNG_WINDOW_SIZE"])
    except Exception as e:
        LOGGER.error(
            "Failed to get PPLNG_WINDOW_SIZE from the environment: {}.  Using default size of {}"
            .format(e, PPLNG_WINDOW_SIZE))

    # Connect to DB
    database = lib.get_db()
    esitmated = [
    ]  # Blocks we know have already been estimated - XXX TODO: Clean paid blocks out of this list

    # Get Config settings
    pool_fee = float(CONFIG[PROCESS]["pool_fee"])

    while True:
        # Generate pool block reward estimates for all new and unlocked blocks
        try:
            database.db.initializeSession()
            unlocked_blocks = Pool_blocks.get_all_unlocked()
            new_blocks = Pool_blocks.get_all_new()
            unlocked_blocks_h = [blk.height for blk in unlocked_blocks]
            new_blocks_h = [blk.height for blk in new_blocks]

            need_estimates = []
            for height in unlocked_blocks_h + new_blocks_h:
                if height not in esitmated:
                    need_estimates.append(height)
            if need_estimates:
                LOGGER.warn("Will ensure estimate for blocks: {}".format(
                    need_estimates))

                # Generate Estimate
                for height in need_estimates:
                    LOGGER.warn("Ensure estimate for block: {}".format(height))
                    payout_map = pool.calculate_block_payout_map(
                        height, PPLNG_WINDOW_SIZE, pool_fee, LOGGER, True)
                    # Double check the total paid is correct
                    esitmated.append(height)
                    LOGGER.warn(
                        "Completed estimate for block: {}".format(height))

                LOGGER.warn("Completed estimates")
            database.db.destroySession()
            sleep(check_interval)
        except Exception as e:  # AssertionError as e:
            LOGGER.error("Something went wrong: {} - {}".format(
                e, traceback.print_stack()))

        LOGGER.warn("=== Completed {}".format(PROCESS))
        sleep(check_interval)
예제 #2
0
def main():
    CONFIG = lib.get_config()
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))
    # Connect to DB
    database = lib.get_db()
    database.db.initializeSession()

    while True:
        # Generate pool block reward estimates for all new and unlocked blocks
        try:
            unlocked_blocks = Pool_blocks.get_all_unlocked()
            unlocked_blocks_h = [blk.height for blk in unlocked_blocks]
            new_blocks = Pool_blocks.get_all_new()
            new_blocks_h = [blk.height for blk in new_blocks]
            LOGGER.warn("Will ensure estimate for blocks: {}".format(
                unlocked_blocks_h + new_blocks_h))

            # Generate Estimate
            for height in unlocked_blocks_h + new_blocks_h:
                LOGGER.warn("Ensure estimate for block: {}".format(height))
                payout_map = pool.calculate_block_payout_map(
                    height, 60, LOGGER, True)
                LOGGER.warn("Completed estimate for block: {}".format(height))

            #database.db.getSession().commit()
            LOGGER.warn("Completed estimates")
            sleep(check_interval)
        except Exception as e:  # AssertionError as e:
            LOGGER.error("Something went wrong: {} - {}".format(
                e, traceback.print_stack()))

        LOGGER.warn("=== Completed {}".format(PROCESS))
        sleep(check_interval)
예제 #3
0
파일: api.py 프로젝트: bitgrin/grin-pool
 def get(self, id, height=0):
     LOGGER = lib.get_logger(PROCESS)
     if id != g.user.id:
         response = jsonify({ 'message': 'Not authorized to access data for other users' })
         response.status_code = 403
         return response
     debug and LOGGER.warn("EstimateApi_payment get id:{} height:{}".format(id, height))
     if height != 0:
         # Request is for a single block reward
         payout_map = pool.get_block_payout_map_estimate(height, LOGGER)
         if payout_map is None:
             return 0
         #print("payout map: {}".format(payout_map))
         #sys.stdout.flush()
         if id in payout_map:
             return payout_map[id]
         else:
             return 0
     # Get a list of all new and unlocked blocks
     unlocked_blocks = Pool_blocks.get_all_unlocked()
     unlocked_blocks_h = [blk.height for blk in unlocked_blocks]
     #LOGGER.warn("EstimateApi_payment unlocked blocks: {}".format(unlocked_blocks))
     new_blocks = Pool_blocks.get_all_new()
     new_blocks_h = [blk.height for blk in new_blocks]
     #LOGGER.warn("EstimateApi_payment new blocks: {}".format(new_blocks))
     total = 0
     for height in unlocked_blocks_h + new_blocks_h:
         debug and print("Estimate block at height: {}".format(height))
         payout_map = pool.get_block_payout_map_estimate(height, LOGGER)
         if payout_map is not None and id in payout_map:
             total = total + payout_map[id]
     return total
예제 #4
0
def main():
    global LOGGER
    global CONFIG
    CONFIG = lib.get_config()
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))

    # Get Config settings
    pool_fee = float(CONFIG[PROCESS]["pool_fee"])
    # Number of blocks of share data used to calculate rewards
    PPLNG_WINDOW_SIZE = 60
    try:
        PPLNG_WINDOW_SIZE = int(os.environ["PPLNG_WINDOW_SIZE"])
    except Exception as e:
        LOGGER.error(
            "Failed to get PPLNG_WINDOW_SIZE from the environment: {}  Using default size of {}"
            .format(e, PPLNG_WINDOW_SIZE))

    # Connect to DB
    database = lib.get_db()

    # Get current blockchain height
    chain_height = grin.blocking_get_current_height()

    # Get unlocked blocks from the db
    unlocked_blocks = Pool_blocks.get_all_unlocked()
    unlocked_blocks = [blk.height for blk in unlocked_blocks]
    LOGGER.warn("Paying for {} pool blocks: {}".format(len(unlocked_blocks),
                                                       unlocked_blocks))
    for height in unlocked_blocks:
        try:
            LOGGER.warn("Processing unlocked block: {}".format(height))
            # Call the library routine to get this blocks payout map
            payout_map = pool.calculate_block_payout_map(
                height, PPLNG_WINDOW_SIZE, pool_fee, LOGGER, False)
            #print("payout_map = {}".format(payout_map))
            # Store the payment map for this block
            credits_record = Pool_credits(chain_height, height, payout_map)
            database.db.getSession().add(credits_record)
            # Make payments based on the workers total share_value
            Pool_blocks.setState(height, "paid")
            for user_id, payment_amount in payout_map.items():
                # Add worker rewards to pool account balance
                LOGGER.warn("Credit to user: {} = {}".format(
                    user_id, payment_amount))
                worker_utxo = Pool_utxo.credit_worker(user_id, payment_amount)
                # Worker_stats accounting and running totals
                #latest_worker_stats = Worker_stats.get_latest_by_id(user_id)
                #latest_worker_stats.dirty = True
            database.db.getSession().commit()

        except Exception as e:
            database.db.getSession().rollback()
            LOGGER.exception("Something went wrong: {}".format(repr(e)))

    LOGGER.warn("=== Completed {}".format(PROCESS))
    sys.stdout.flush()
예제 #5
0
def main():
    global LOGGER
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))

    # Connect to DB
    database = lib.get_db()

    latest_block = 0

    # XXX All in one db transaction....
    # Get unlocked blocks from the db
    unlocked_blocks = Pool_blocks.get_all_unlocked()
    database.db.getSession().commit()
    for pb in unlocked_blocks:
        try:
            LOGGER.warn("Processing unlocked block: {}".format(pb))
            if pb.height > latest_block:
                latest_block = pb.height
            # Get valid pool_shares for that block from the db
            pool_shares = Pool_shares.get_valid_by_height(pb.height)
            # Calculate Payment info:
            worker_shares = {}
            for ps in pool_shares:
                LOGGER.warn("Processing pool_shares: {}".format(ps))
                # Need to get actual_difficulty
                gs = Grin_shares.get_by_nonce(ps.nonce)
                if gs == None:
                    # XXX NOTE: no payout for shares not accepted by grin node
                    continue
                if ps.found_by in worker_shares:
                    worker_shares[ps.found_by] += gs.actual_difficulty
                else:
                    worker_shares[ps.found_by] = gs.actual_difficulty
            if len(worker_shares) > 0:
                # Calcualte reward/difficulty: XXX TODO: Enhance
                #  What algorithm to use?  Maybe: https://slushpool.com/help/manual/rewards
                r_per_d = REWARD / sum(worker_shares.values())
                for worker in worker_shares.keys():
                    # Calculate reward per share
                    worker_rewards = worker_shares[worker] * r_per_d
                    # Add or create worker rewards
                    worker_utxo = Pool_utxo.credit_worker(
                        worker, worker_rewards)
                    LOGGER.warn("Credit to user: {} = {}".format(
                        worker, worker_rewards))
            # Mark the pool_block state="paid" (maybe "processed" would be more accurate?)
            pb.state = "paid"
            database.db.getSession().commit()
        except Exception as e:
            database.db.getSession().rollback()
            LOGGER.error("Something went wrong: {}".format(e))

    #database.db.getSession().commit()
    # db.set_last_run(PROCESS, str(time.time()))
    LOGGER.warn("=== Completed {}".format(PROCESS))
    sys.stdout.flush()
예제 #6
0
def main():
    global LOGGER
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))

    # Connect to DB
    database = lib.get_db()

    latest_block = 0

    # XXX All in one db transaction....
    # Get unlocked blocks from the db
    unlocked_blocks = Pool_blocks.get_all_unlocked()
    database.db.getSession().commit()
    for pb in unlocked_blocks:
        try:
            LOGGER.warn("Processing unlocked block: {}".format(pb))
            if pb.height > latest_block:
                latest_block = pb.height
            # Get Worker_stats of this block to calculate reward for each worker
            worker_stats = Worker_stats.get_by_height(pb.height)
            # Calculate Payment info:
            if len(worker_stats) > 0:
                # Calcualte reward/share:
                # XXX TODO: Enhance
                #  What algorithm to use?  Maybe: https://slushpool.com/help/manual/rewards
                r_per_g = REWARD / sum([st.gps for st in worker_stats])
                for stat in worker_stats:
                    # Calculate reward
                    worker_rewards = stat.gps * r_per_g
                    # Add or create worker rewards
                    worker_utxo = Pool_utxo.credit_worker(
                        stat.worker, worker_rewards)
                    LOGGER.warn("Credit to user: {} = {}".format(
                        stat.worker, worker_rewards))
            # Mark the pool_block state="paid" (maybe "processed" would be more accurate?)
            pb.state = "paid"
            database.db.getSession().commit()
        except Exception as e:
            database.db.getSession().rollback()
            LOGGER.error("Something went wrong: {}".format(e))

    #database.db.getSession().commit()
    LOGGER.warn("=== Completed {}".format(PROCESS))
    sys.stdout.flush()
예제 #7
0
def main():
    global LOGGER
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))

    # Connect to DB
    database = lib.get_db()

    # XXX All in one db transaction....
    # Get unlocked blocks from the db
    unlocked_blocks = Pool_blocks.get_all_unlocked()
    unlocked_blocks = [blk.height for blk in unlocked_blocks]
    for height in unlocked_blocks:
        try:
            LOGGER.warn("Processing unlocked block: {}".format(height))
            # Call the library routine to get this blocks payout map
            payout_map = pool.calculate_block_payout_map(
                height, PPLNS_WINDOW, LOGGER, False)
            #print("payout_map = {}".format(payout_map))
            # Make payments based on the workers total share_value
            Pool_blocks.setState(height, "paid")
            database.db.getSession().commit()
            for user_id, payment_amount in payout_map.items():
                # Add worker rewards to pool account balance
                LOGGER.warn("Credit to user: {} = {}".format(
                    user_id, payment_amount))
                worker_utxo = Pool_utxo.credit_worker(user_id, payment_amount)
                # Worker_stats accounting and running totals
                #latest_worker_stats = Worker_stats.get_latest_by_id(user_id)
                #latest_worker_stats.dirty = True
            database.db.getSession().commit()

        except Exception as e:
            database.db.getSession().rollback()
            LOGGER.error("Something went wrong: {} - {}".format(
                e, traceback.print_exc()))

    LOGGER.warn("=== Completed {}".format(PROCESS))
    sys.stdout.flush()
예제 #8
0
파일: api.py 프로젝트: waosman/grin-pool
 def get(self, id, height=None, range=None):
     LOGGER = lib.get_logger(PROCESS)
     if id != g.user.id:
         response = jsonify(
             {'message': 'Not authorized to access data for other users'})
         response.status_code = 403
         return response
     debug and LOGGER.warn("EstimateApi_payment get id:{} height:{}".format(
         id, height))
     id_str = str(id)
     if height is None:
         # Immature Balance Estimate
         LOGGER.warn("Immature Balance Estimate")
         # Get a list of all new and unlocked blocks
         unlocked_blocks = Pool_blocks.get_all_unlocked()
         unlocked_blocks_h = [blk.height for blk in unlocked_blocks]
         #LOGGER.warn("EstimateApi_payment unlocked blocks: {}".format(unlocked_blocks))
         new_blocks = Pool_blocks.get_all_new()
         new_blocks_h = [blk.height for blk in new_blocks]
         #LOGGER.warn("EstimateApi_payment new blocks: {}".format(new_blocks))
         total = 0
         for height in unlocked_blocks_h + new_blocks_h:
             debug and print("Estimate block at height: {}".format(height))
             payout_map = pool.get_block_payout_map_estimate(height, LOGGER)
             if payout_map is not None and id_str in payout_map:
                 total = total + payout_map[id_str]
         return {"immature": total}
     if type(height) == str:
         if height == "next":
             # Next block estimate
             debug and LOGGER.warn("Next block estimate")
             estimate = 0
             payout_map = pool.get_block_payout_map_estimate(height, LOGGER)
             if payout_map is None:
                 estimate = "TBD"
             elif id_str in payout_map:
                 estimate = payout_map[id_str]
             else:
                 estimate = 0
             return {"next": estimate}
         else:
             response = jsonify({'message': 'Invalid Request'})
             response.status_code = 400
             return response
     # Block Reward estimate
     if range is None:
         # One specific block estimate
         debug and LOGGER.warn("One specific block estimate")
         estimate = 0
         payout_map = pool.get_block_payout_map_estimate(height, LOGGER)
         if payout_map is not None:
             if id_str in payout_map.keys():
                 estimate = payout_map[id_str]
             else:
                 estimate = 0
         else:
             # Maybe this is a pool block but we didnt estimate it yet
             pb = Pool_blocks.get_by_height(height)
             if pb is not None:
                 estimate = "TBD"
         str_height = str(height)
         return {str_height: estimate}
     # Range of pool block reward estimates
     debug and LOGGER.warn("Range of blocks estimate")
     # Enforce range limit
     range = min(range, pool_blocks_range_limit)
     # Get the list of pool block(s) heights
     if height == 0:
         blocks = Pool_blocks.get_latest(range)
     else:
         blocks = Pool_blocks.get_by_height(height, range)
     block_heights = [pb.height for pb in blocks]
     # Get estimates for each of the blocks
     estimates = {}
     for height in block_heights:
         estimate = 0
         payout_map = pool.get_block_payout_map_estimate(height, LOGGER)
         if payout_map is None:
             estimate = "TBD"
         elif id_str in payout_map:
             estimate = payout_map[id_str]
         else:
             estimate = 0
         str_height = str(height)
         estimates[str_height] = estimate
     return estimates
예제 #9
0
def main():
    global LOGGER
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))

    # Connect to DB
    database = lib.get_db()

    latest_block = 0

    # XXX All in one db transaction....
    # Get unlocked blocks from the db
    unlocked_blocks = Pool_blocks.get_all_unlocked()
    database.db.getSession().commit()
    for pb in unlocked_blocks:
        try:
            LOGGER.warn("Processing unlocked block: {}".format(pb))
            if pb.height > latest_block:
                latest_block = pb.height
            # Get Worker_stats of this block + range to calculate reward for each worker
            worker_shares_window = Worker_shares.get_by_height(pb.height, PPLNS_WINDOW)
            print("worker_shares_window = {}".format(worker_shares_window))
            # Calculate Payment info:
            if len(worker_shares_window) > 0:
                # Calcualte reward/share:
                # XXX TODO: Enhance
                #  What algorithm to use?  Maybe: https://slushpool.com/help/manual/rewards
                # For now, some variation on pplns

                # Sum up the number of each size share submitted by each user
                shares_count_map = {}
                for worker_shares_rec in worker_shares_window:
                    if not worker_shares_rec.worker in shares_count_map:
                        shares_count_map[worker_shares_rec.worker] = {}
                    for pow_size in worker_shares_rec.sizes():
                        print("pow_size = {}".format(pow_size))
                        if not pow_size in shares_count_map[worker_shares_rec.worker]:
                            shares_count_map[worker_shares_rec.worker][pow_size] = 0
                        shares_count_map[worker_shares_rec.worker][pow_size] += worker_shares_rec.num_valid(pow_size)
                print("Shares Count Map:")
                pp.pprint(shares_count_map)

                # Normalize and sum each workers shares to create a "share value"
                total_value = 0
                for worker, worker_shares_count in shares_count_map.items():
                    print("worker: {}, worker_shares_count: {}".format(worker, worker_shares_count))
                    sizes = list(worker_shares_count.keys())
                    print("sizes: {}".format(sizes))
                    shares_count_map[worker]["value"] = 0
                    value = 0
                    for size, count in worker_shares_count.items():
                        if size == 29:
                            value += float(count) * .33
                        else:
                            value += float(count)
                        total_value += value
                    shares_count_map[worker]["value"] = value
                    print("Worker {} value: {}".format(worker, value))
                
                # Make payments based on the workers total share_value
                for worker, worker_shares_count in shares_count_map.items():
                    worker_rewards = REWARD * worker_shares_count["value"] / total_value
                    # Add or create worker rewards
                    worker_utxo = Pool_utxo.credit_worker(worker, worker_rewards)
                    LOGGER.warn("Credit to user: {} = {}".format(worker, worker_rewards))
            # Mark the pool_block state="paid" (maybe "processed" would be more accurate?)
            pb.state = "paid"
            database.db.getSession().commit()
        except Exception as e:
            database.db.getSession().rollback()
            LOGGER.error("Something went wrong: {} - {}".format(e, traceback.print_exc()))

    #database.db.getSession().commit()
    LOGGER.warn("=== Completed {}".format(PROCESS))
    sys.stdout.flush()
예제 #10
0
def main():
    global CONFIG
    global LOGGER
    CONFIG = lib.get_config()
    LOGGER = lib.get_logger(PROCESS)
    LOGGER.warn("=== Starting {}".format(PROCESS))

    # Number of blocks of share data used to calculate rewards
    PPLNG_WINDOW_SIZE = 60
    try:
        PPLNG_WINDOW_SIZE = int(os.environ["PPLNG_WINDOW_SIZE"])
    except Exception as e:
        LOGGER.error(
            "Failed to get PPLNG_WINDOW_SIZE from the environment: {}.  Using default size of {}"
            .format(e, PPLNG_WINDOW_SIZE))

    POOL_FEE = 0.0075
    try:
        POOL_FEE = float(CONFIG[PROCESS]["pool_fee"])
    except Exception as e:
        LOGGER.error(
            "Failed to get POOL_FEE from the config: {}.  Using default fee of {}"
            .format(e, POOL_FEE))

    # Keep track of "next" block estimated
    next_height_estimated = 0

    # Connect to DB
    database = lib.get_db()

    while True:
        # Generate pool block reward estimates for all new and unlocked blocks
        try:
            database.db.initializeSession()
            next_height = Blocks.get_latest(
            ).height - 5  # A recent height which all worker shares are available
            unlocked_blocks = Pool_blocks.get_all_unlocked()
            new_blocks = Pool_blocks.get_all_new()
            unlocked_blocks_h = [blk.height for blk in unlocked_blocks]
            new_blocks_h = [blk.height for blk in new_blocks]

            need_estimates = unlocked_blocks_h + new_blocks_h
            LOGGER.warn(
                "Will ensure estimate for blocks: {}".format(need_estimates))
            redisdb = lib.get_redis_db()

            # Generate Estimate
            for height in need_estimates:
                if height > next_height:
                    LOGGER.warn(
                        "Delay estimate until we have recent shares availalbe for block: {}"
                        .format(height))
                else:
                    LOGGER.warn("Ensure estimate for block: {}".format(height))
                    # Check if we already have an estimate cached
                    payout_estimate_map_key = key_prefix + str(height)
                    cached_map = redisdb.get(payout_estimate_map_key)
                    if cached_map is None:
                        # We dont have it cached, we need to calcualte it and cache it now
                        payout_map = pool.calculate_block_payout_map(
                            height, PPLNG_WINDOW_SIZE, POOL_FEE, LOGGER, True)
                        payout_map_json = json.dumps(payout_map)
                        redisdb.set(payout_estimate_map_key,
                                    payout_map_json,
                                    ex=cache_expire)
                        LOGGER.warn(
                            "Created estimate for block {} with key {}".format(
                                height, payout_estimate_map_key))
                    else:
                        LOGGER.warn(
                            "There is an exiting estimate for block: {}".
                            format(height))

            # Generate estimate for "next" block
            LOGGER.warn(
                "Ensure estimate for next block: {}".format(next_height))
            if next_height_estimated != next_height:
                payout_map = pool.calculate_block_payout_map(
                    next_height, PPLNG_WINDOW_SIZE, POOL_FEE, LOGGER, True)
                payout_map_json = json.dumps(payout_map)
                payout_estimate_map_key = key_prefix + "next"
                redisdb.set(payout_estimate_map_key,
                            payout_map_json,
                            ex=cache_expire)
                next_height_estimated = next_height
                LOGGER.warn("Created estimate for block {} with key {}".format(
                    next_height, payout_estimate_map_key))
            else:
                LOGGER.warn(
                    "There is an exiting next block estimate for : {}".format(
                        next_height))

            LOGGER.warn("Completed estimates")
            database.db.destroySession()
            # Flush debug print statements
            sys.stdout.flush()
        except Exception as e:  # AssertionError as e:
            LOGGER.error("Something went wrong: {} - {}".format(
                e, traceback.format_exc()))
            database.db.destroySession()

        LOGGER.warn("=== Completed {}".format(PROCESS))
        sleep(check_interval)