# Path: feemodel/config.py
# DIFF_RETARGET_INTERVAL = 2016
# PRIORITYTHRESH = 57600000
# EXPECTED_BLOCK_INTERVAL = 600
# MINRELAYTXFEE = 5000
# def read_default_config():
# 
# Path: feemodel/util.py
# class StoppableThread(threading.Thread):
# class WorkerThread(threading.Thread):
# class BlockingProxy(Proxy):
# class CacheProxy(BlockingProxy):
# class BatchProxy(CacheProxy):
# class DataSample(object):
# class Function(object):
# class DiscreteFunction(Function):
# class StepFunction(Function):
# class BlockMetadata(object):
#     def __init__(self):
#     def run(self):
#     def stop(self):
#     def is_stopped(self):
#     def sleep(self, secs):
#     def context_start(self):
#     def get_stop_object(self):
#     def auto_restart(interval):
#         def decorator(fn):
#             def looped_fn(self, *args, **kwargs):
# def logexceptions(fn):
#     def logged_fn(*args, **kwargs):
#     def __init__(self, workfn):
#     def run(self):
#     def put(self, *args):
#     def stop(self):
#     def __init__(self):
#     def _call(self, *args):
#     def close(self):
#     def __init__(self, maxblocks=10, maxhashes=1000):
#     def getcache(self, d, key, maxitems, default_fn):
#     def getblock(self, blockhash):
#     def getblockhash(self, blockheight):
#     def poll_mempool(self):
#     def __init__(self, datapoints=None):
#     def add_datapoints(self, datapoints):
#     def calc_stats(self):
#     def get_percentile(self, p, weights=None):
#     def __len__(self):
#     def __repr__(self):
#     def __init__(self, x, y):
#     def __call__(self, x0, use_upper=False, use_lower=False):
#     def inv(self, y0, use_upper=False, use_lower=False):
#     def addpoint(self, xi, yi):
#     def __getitem__(self, idx):
#     def __str__(self):
#     def __len__(self):
#     def __iter__(self):
#     def __copy__(self):
#     def __call__(self, x0):
#     def inv(self, y0):
#     def __call__(self, x0):
#     def approx(self, percenterror=0.05, percentstep=0.05):
#     def _get_maxerror(self, previdx, curridx, f):
#     def __copy__(self):
#     def __init__(self, height):
#     def get_poolname(self):
#     def __repr__(self):
# def save_obj(obj, filename, protocol=2):
# def load_obj(filename):
# def get_coinbase_info(blockheight):
# def get_hashesperblock(blockheight):
# def get_block_timestamp(blockheight):
# def get_block_size(blockheight):
# def get_block_name(blockheight):
# def get_feerate(rawentry):
# def round_random(f):
# def interpolate(x0, x, y):
# def cumsum_gen(iterable, base=0, mapfn=lambda x: x):
#     STOP = StopIteration()


import os
import threading
import sqlite3
import decimal
import logging
from time import time
from copy import copy
from itertools import groupby
from operator import attrgetter, itemgetter
from bitcoin.core import b2lx
from feemodel.config import config, datadir, MINRELAYTXFEE, PRIORITYTHRESH
from feemodel.util import (proxy, StoppableThread, get_feerate, WorkerThread,
                           cumsum_gen, BlockMetadata, StepFunction)
from feemodel.stranding import tx_preprocess, calc_stranding_feerate
from feemodel.simul.simul import SimEntry

    If the block count has increased in between polls, we record:
        1. Transactions in the mempool just prior to block discovery
        2. For each transaction, whether or not it was included in the block.

    The goal is to make inferences about the transaction selection policies
    of miners.

    The polling is done via batch call; however, they are not processed
    atomically by Bitcoin Core - there is the probability of a race condition
    in which the block count increases in between processing the two requests.
    In this case the statistics for that block will be somewhat degraded.

    In addition, chain re-orgs are not handled. If a re-org happens, the
    transactions that we record are not necessarily representative of the
    pool of valid transactions seen by the miner. Any inference algorithm
    must be tolerant of such errors, in addition to any other kinds of network
    errors.
    '''

    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__()


# Path: feemodel/config.py
# DIFF_RETARGET_INTERVAL = 2016
# PRIORITYTHRESH = 57600000
# EXPECTED_BLOCK_INTERVAL = 600
# MINRELAYTXFEE = 5000
# def read_default_config():
# 
# Path: feemodel/util.py
# class StoppableThread(threading.Thread):
# class WorkerThread(threading.Thread):
# class BlockingProxy(Proxy):
# class CacheProxy(BlockingProxy):
# class BatchProxy(CacheProxy):
# class DataSample(object):
# class Function(object):
# class DiscreteFunction(Function):
# class StepFunction(Function):
# class BlockMetadata(object):
#     def __init__(self):
#     def run(self):
#     def stop(self):
#     def is_stopped(self):
#     def sleep(self, secs):
#     def context_start(self):
#     def get_stop_object(self):
#     def auto_restart(interval):
#         def decorator(fn):
#             def looped_fn(self, *args, **kwargs):
# def logexceptions(fn):
#     def logged_fn(*args, **kwargs):
#     def __init__(self, workfn):
#     def run(self):
#     def put(self, *args):
#     def stop(self):
#     def __init__(self):
#     def _call(self, *args):
#     def close(self):
#     def __init__(self, maxblocks=10, maxhashes=1000):
#     def getcache(self, d, key, maxitems, default_fn):
#     def getblock(self, blockhash):
#     def getblockhash(self, blockheight):
#     def poll_mempool(self):
#     def __init__(self, datapoints=None):
#     def add_datapoints(self, datapoints):
#     def calc_stats(self):
#     def get_percentile(self, p, weights=None):
#     def __len__(self):
#     def __repr__(self):
#     def __init__(self, x, y):
#     def __call__(self, x0, use_upper=False, use_lower=False):
#     def inv(self, y0, use_upper=False, use_lower=False):
#     def addpoint(self, xi, yi):
#     def __getitem__(self, idx):
#     def __str__(self):
#     def __len__(self):
#     def __iter__(self):
#     def __copy__(self):
#     def __call__(self, x0):
#     def inv(self, y0):
#     def __call__(self, x0):
#     def approx(self, percenterror=0.05, percentstep=0.05):
#     def _get_maxerror(self, previdx, curridx, f):
#     def __copy__(self):
#     def __init__(self, height):
#     def get_poolname(self):
#     def __repr__(self):
# def save_obj(obj, filename, protocol=2):
# def load_obj(filename):
# def get_coinbase_info(blockheight):
# def get_hashesperblock(blockheight):
# def get_block_timestamp(blockheight):
# def get_block_size(blockheight):
# def get_block_name(blockheight):
# def get_feerate(rawentry):
# def round_random(f):
# def interpolate(x0, x, y):
# def cumsum_gen(iterable, base=0, mapfn=lambda x: x):
#     STOP = StopIteration()


# Path: feemodel/txmempool.py
import os
import threading
import sqlite3
import decimal
import logging
from time import time
from copy import copy
from itertools import groupby
from operator import attrgetter, itemgetter
from bitcoin.core import b2lx
from feemodel.config import config, datadir, MINRELAYTXFEE, PRIORITYTHRESH
from feemodel.util import (proxy, StoppableThread, get_feerate, WorkerThread,
                           cumsum_gen, BlockMetadata, StepFunction)
from feemodel.stranding import tx_preprocess, calc_stranding_feerate
from feemodel.simul.simul import SimEntry


    If the block count has increased in between polls, we record:
        1. Transactions in the mempool just prior to block discovery
        2. For each transaction, whether or not it was included in the block.

    The goal is to make inferences about the transaction selection policies
    of miners.

    The polling is done via batch call; however, they are not processed
    atomically by Bitcoin Core - there is the probability of a race condition
    in which the block count increases in between processing the two requests.
    In this case the statistics for that block will be somewhat degraded.

    In addition, chain re-orgs are not handled. If a re-org happens, the
    transactions that we record are not necessarily representative of the
    pool of valid transactions seen by the miner. Any inference algorithm
    must be tolerant of such errors, in addition to any other kinds of network
    errors.
    '''

    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__()


    @StoppableThread.auto_restart(60)