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)))
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)))
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)
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)
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__()
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)
def __init__(self, host=config.get("client", "host"), port=config.getint("client", "port")): self.host = host self.port = port
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)
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)