예제 #1
0
 def load_predicts(self):
     try:
         self.prediction = load_obj(PREDICT_SAVEFILE)
     except Exception:
         logger.info("Unable to load saved predicts; "
                     "starting from scratch.")
         self.prediction = Prediction(
             config.getint("app", "predict_block_halflife"),
             blocks_to_keep=config.getint("app", "predict_blocks_to_keep"))
     else:
         logger.info("Prediction loaded with {} saved predicts.".
                     format(len(self.prediction.predicts)))
예제 #2
0
 def load_predicts(self):
     try:
         self.prediction = load_obj(PREDICT_SAVEFILE)
     except Exception:
         logger.info("Unable to load saved predicts; "
                     "starting from scratch.")
         self.prediction = Prediction(
             config.getint("app", "predict_block_halflife"),
             blocks_to_keep=config.getint("app", "predict_blocks_to_keep"))
     else:
         logger.info("Prediction loaded with {} saved predicts.".format(
             len(self.prediction.predicts)))
예제 #3
0
    def __init__(self, txsource_init=None):
        super(SimOnline, self).__init__()
        self.predictworker = WorkerThread(self.update_predicts)
        self.load_predicts()

        currheight = feemodel.util.proxy.getblockcount()
        self.poolsonline = PoolsOnlineEstimator(
            currheight,
            self.get_stop_object(),
            config.getint("app", "pools_window"),
            minblocks=config.getint("app", "pools_minblocks"))
        self.txonline = TxRateOnlineEstimator(
            txsource_init=txsource_init,
            halflife=config.getint("app", "txrate_halflife"))

        trans_numprocesses = config.getint("app", "trans_numprocesses")
        if trans_numprocesses == -1:
            trans_numprocesses = None
        self.transient = TransientOnline(
            self,
            self.poolsonline,
            self.txonline,
            update_period=config.getint("app", "trans_update_period"),
            miniters=config.getint("app", "trans_miniters"),
            maxiters=config.getint("app", "trans_maxiters"),
            numprocesses=trans_numprocesses)
예제 #4
0
    def __init__(self, txsource_init=None):
        super(SimOnline, self).__init__()
        self.predictworker = WorkerThread(self.update_predicts)
        self.load_predicts()

        currheight = feemodel.util.proxy.getblockcount()
        self.poolsonline = PoolsOnlineEstimator(
            currheight,
            self.get_stop_object(),
            config.getint("app", "pools_window"),
            minblocks=config.getint("app", "pools_minblocks"))
        self.txonline = TxRateOnlineEstimator(txsource_init=txsource_init,
                                              halflife=config.getint(
                                                  "app", "txrate_halflife"))

        trans_numprocesses = config.getint("app", "trans_numprocesses")
        if trans_numprocesses == -1:
            trans_numprocesses = None
        self.transient = TransientOnline(
            self,
            self.poolsonline,
            self.txonline,
            update_period=config.getint("app", "trans_update_period"),
            miniters=config.getint("app", "trans_miniters"),
            maxiters=config.getint("app", "trans_maxiters"),
            numprocesses=trans_numprocesses)
예제 #5
0
 def __init__(self, dbfile=MEMBLOCK_DBFILE,
              blocks_to_keep=config.getint("txmempool", "blocks_to_keep"),
              poll_period=config.getfloat("txmempool", "poll_period")):
     self.state = None
     self.blockworker = None
     self.dbfile = dbfile
     self.blocks_to_keep = blocks_to_keep
     self.poll_period = poll_period
     super(TxMempool, self).__init__()
예제 #6
0
 def __init__(self,
              dbfile=MEMBLOCK_DBFILE,
              blocks_to_keep=config.getint("txmempool", "blocks_to_keep"),
              poll_period=config.getfloat("txmempool", "poll_period")):
     self.state = None
     self.blockworker = None
     self.dbfile = dbfile
     self.blocks_to_keep = blocks_to_keep
     self.poll_period = poll_period
     super(TxMempool, self).__init__()
예제 #7
0
    def test_A(self):
        """Basic tests."""
        config.set("app", "pools_minblocks", "1")
        sim = SimOnline()
        print("Starting test A thread.")
        with sim.context_start():
            while not sim.txonline.tx_estimator:
                sleep(0.1)
            while not sim.transient.stats:
                sleep(0.1)
            transient_stats = sim.transient.stats
            print(transient_stats.expectedwaits)
            lowest_feerate = transient_stats.feepoints[0]
            print("*** Setting rawmempool to 333931 ***")
            proxy.set_rawmempool(333953)
            sleep(poll_period)
            for txid, predict in sim.prediction.predicts.items():
                if predict is not None:
                    predict.entrytime = self.time() - 600
                else:
                    entry = sim.state.entries[txid]
                    self.assertTrue(
                        entry.is_high_priority() or
                        entry.depends or
                        entry.feerate < lowest_feerate)
            print("*** Incrementing blockcount ***")
            proxy.blockcount += 1
            proxy.rawmempool = {}
            sleep(poll_period*2)
            predictstats = sim.get_predictstats()
            pprint(zip(*predictstats['pval_ecdf']))
            print("p-distance is {}".format(predictstats['pdistance']))
            pred_db = Prediction.from_db(
                config.getint("app", "predict_block_halflife"))
            self.assertEqual(pred_db.pval_ecdf, sim.prediction.pval_ecdf)
            self.assertEqual(sum(sim.prediction.pvalcounts), 76)

            poolsref = sim.poolsonline.get_pools()
            predictionref = sim.prediction

        # Test loading of predicts and pools
        # config.set("app", "pools_minblocks", "432")
        sim = SimOnline()
        with sim.context_start():
            sleep(1)
            self.assertTrue(sim.poolsonline.poolsestimate)
            self.assertEqual(poolsref, sim.poolsonline.get_pools())
            self.assertEqual(predictionref, sim.prediction)
예제 #8
0
 def __init__(self,
              host=config.get("client", "host"),
              port=config.getint("client", "port")):
     self.host = host
     self.port = port
예제 #9
0
def main(mempool_only=False, txsourcefile=None):
    configure_logger()
    signal.signal(signal.SIGTERM, sigterm_handler)

    app = make_json_app(__name__)
    if mempool_only:
        sim = TxMempool()
    else:
        if txsourcefile is not None:
            txsource_init = load_obj(txsourcefile)
            txsource_init.prevstate = None
        else:
            txsource_init = None
        sim = SimOnline(txsource_init=txsource_init)

    @app.route('/feemodel/mempool', methods=['GET'])
    def mempool():
        stats = sim.get_stats()
        if stats is None:
            abort(503)
        return jsonify(sim.get_stats())

    @app.route('/feemodel/transient', methods=['GET'])
    def transient():
        try:
            stats = sim.get_transientstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    @app.route('/feemodel/pools', methods=['GET'])
    def pools():
        try:
            stats = sim.get_poolstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    # TODO: refuse to send if request is external
    @app.route('/feemodel/poolsobj', methods=['GET'])
    def poolsobj():
        """Get the pickled representation of current SimPools obj."""
        try:
            poolsestimate = sim.poolsonline.get_pools()
        except AttributeError:
            abort(501)
        poolspickle_b64 = b64encode(pickle.dumps(poolsestimate, protocol=2))
        obj = {"poolspickle_b64": poolspickle_b64}
        return jsonify(obj)

    @app.route('/feemodel/prediction', methods=['GET'])
    def prediction():
        try:
            stats = sim.get_predictstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    @app.route('/feemodel/txrate', methods=['GET'])
    def txrate():
        try:
            stats = sim.get_txstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    @app.route('/feemodel/txsourceobj', methods=['GET'])
    def txsourceobj():
        """Get the pickled representation of the current SimTxSource obj."""
        try:
            tx_estimator = sim.txonline.get_txsource()
        except AttributeError:
            abort(501)
        tx_estimator_b64 = b64encode(pickle.dumps(tx_estimator, protocol=2))
        obj = {"tx_estimator_b64": tx_estimator_b64}
        return jsonify(obj)

    @app.route('/feemodel/estimatefee/<int:waitminutes>', methods=['GET'])
    def estimatefee(waitminutes):
        # TODO: check if it transient stats are outdated.
        try:
            stats = sim.transient.stats
        except AttributeError:
            abort(501)
        if stats is None:
            abort(503)
        feerate = stats.estimatefee(waitminutes)
        if feerate is None:
            feerate = -1
        response = {'feerate': feerate, 'avgwait': waitminutes}
        return jsonify(response)

    @app.route('/feemodel/decidefee', methods=['GET'])
    def decidefee():
        try:
            stats = sim.transient.stats
        except AttributeError:
            abort(501)
        if stats is None:
            abort(503)
        try:
            data = request.get_json(force=True)
            waitcostfn = data['waitcostfn']
            txsize = data['txsize']
            ten_minute_cost = data['tenmincost']
        except Exception:
            abort(400)
        try:
            fee, expectedwait, totalcost = stats.decidefee(
                txsize, ten_minute_cost, waitcostfn=waitcostfn)
            assert isinstance(txsize, int)
            assert txsize > 0
            assert isinstance(ten_minute_cost, int)
            assert ten_minute_cost > 0
        except (ValueError, AssertionError):
            response = {'message': '400: bad arguments.'}
            return make_response(jsonify(response), 400)
        response = {
            "fee": fee,
            "feerate": fee * 1000 / txsize,
            "expectedwait": expectedwait,
            "totalcost": totalcost
        }
        return jsonify(response)

    @app.route('/feemodel/loglevel', methods=['GET', 'PUT'])
    def loglevel():
        if request.method == 'PUT':
            try:
                data = request.get_json(force=True)
                levelname = data['level'].upper()
                loglevel = LOG_LEVELS[levelname]
            except Exception:
                response = {'message': '400: bad log level.'}
                return make_response(jsonify(response), 400)
            else:
                logger.setLevel(loglevel)
        response = {"level": logging.getLevelName(logger.level)}
        return jsonify(response)

    with sim.context_start():
        host = config.get("app", "host")
        port = config.getint("app", "port")
        print("Logging to {}".format(logfile))
        logger.info("Listening on http://{}:{}".format(host, port))
        # app.run(port=port, debug=True, use_reloader=False)
        logger.info("{} v{}".format(pkgname, __version__))
        app.run(host=host, port=port)
예제 #10
0
def main(mempool_only=False, txsourcefile=None):
    configure_logger()
    signal.signal(signal.SIGTERM, sigterm_handler)

    app = make_json_app(__name__)
    if mempool_only:
        sim = TxMempool()
    else:
        if txsourcefile is not None:
            txsource_init = load_obj(txsourcefile)
            txsource_init.prevstate = None
        else:
            txsource_init = None
        sim = SimOnline(txsource_init=txsource_init)

    @app.route('/feemodel/mempool', methods=['GET'])
    def mempool():
        stats = sim.get_stats()
        if stats is None:
            abort(503)
        return jsonify(sim.get_stats())

    @app.route('/feemodel/transient', methods=['GET'])
    def transient():
        try:
            stats = sim.get_transientstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    @app.route('/feemodel/pools', methods=['GET'])
    def pools():
        try:
            stats = sim.get_poolstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    # TODO: refuse to send if request is external
    @app.route('/feemodel/poolsobj', methods=['GET'])
    def poolsobj():
        """Get the pickled representation of current SimPools obj."""
        try:
            poolsestimate = sim.poolsonline.get_pools()
        except AttributeError:
            abort(501)
        poolspickle_b64 = b64encode(pickle.dumps(poolsestimate, protocol=2))
        obj = {"poolspickle_b64": poolspickle_b64}
        return jsonify(obj)

    @app.route('/feemodel/prediction', methods=['GET'])
    def prediction():
        try:
            stats = sim.get_predictstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    @app.route('/feemodel/txrate', methods=['GET'])
    def txrate():
        try:
            stats = sim.get_txstats()
        except AttributeError:
            abort(501)
        return jsonify(stats)

    @app.route('/feemodel/txsourceobj', methods=['GET'])
    def txsourceobj():
        """Get the pickled representation of the current SimTxSource obj."""
        try:
            tx_estimator = sim.txonline.get_txsource()
        except AttributeError:
            abort(501)
        tx_estimator_b64 = b64encode(pickle.dumps(tx_estimator, protocol=2))
        obj = {"tx_estimator_b64": tx_estimator_b64}
        return jsonify(obj)

    @app.route('/feemodel/estimatefee/<int:waitminutes>', methods=['GET'])
    def estimatefee(waitminutes):
        # TODO: check if it transient stats are outdated.
        try:
            stats = sim.transient.stats
        except AttributeError:
            abort(501)
        if stats is None:
            abort(503)
        feerate = stats.estimatefee(waitminutes)
        if feerate is None:
            feerate = -1
        response = {'feerate': feerate, 'avgwait': waitminutes}
        return jsonify(response)

    @app.route('/feemodel/decidefee', methods=['GET'])
    def decidefee():
        try:
            stats = sim.transient.stats
        except AttributeError:
            abort(501)
        if stats is None:
            abort(503)
        try:
            data = request.get_json(force=True)
            waitcostfn = data['waitcostfn']
            txsize = data['txsize']
            ten_minute_cost = data['tenmincost']
        except Exception:
            abort(400)
        try:
            fee, expectedwait, totalcost = stats.decidefee(
                txsize, ten_minute_cost, waitcostfn=waitcostfn)
            assert isinstance(txsize, int)
            assert txsize > 0
            assert isinstance(ten_minute_cost, int)
            assert ten_minute_cost > 0
        except (ValueError, AssertionError):
            response = {'message': '400: bad arguments.'}
            return make_response(jsonify(response), 400)
        response = {
            "fee": fee,
            "feerate": fee*1000/txsize,
            "expectedwait": expectedwait,
            "totalcost": totalcost
        }
        return jsonify(response)

    @app.route('/feemodel/loglevel', methods=['GET', 'PUT'])
    def loglevel():
        if request.method == 'PUT':
            try:
                data = request.get_json(force=True)
                levelname = data['level'].upper()
                loglevel = LOG_LEVELS[levelname]
            except Exception:
                response = {'message': '400: bad log level.'}
                return make_response(jsonify(response), 400)
            else:
                logger.setLevel(loglevel)
        response = {"level": logging.getLevelName(logger.level)}
        return jsonify(response)

    with sim.context_start():
        host = config.get("app", "host")
        port = config.getint("app", "port")
        print("Logging to {}".format(logfile))
        logger.info("Listening on http://{}:{}".format(host, port))
        # app.run(port=port, debug=True, use_reloader=False)
        logger.info("{} v{}".format(pkgname, __version__))
        app.run(host=host, port=port)