# Path: feemodel/tests/config.py
# def tmpdatadir_context():
# def load_obj(filename):
# def mk_tmpdatadir():
# def rm_tmpdatadir():
#     README = ("This is a temporary directory for feemodel unit tests,\n"
#               "and is meant to be removed after every test. Feel free\n"
#               "to delete it if it failed to be removed.\n")
# 
# Path: feemodel/tests/pseudoproxy.py
# def install():
#     '''Substitutes the real proxy with our pseudo one.'''
#     feemodel.util.proxy = proxy
#     feemodel.txmempool.proxy = proxy
# 
# Path: feemodel/util.py
# def save_obj(obj, filename, protocol=2):
#     '''Convenience function to pickle an object to disk.'''
#     with open(filename, 'wb') as f:
#         pickle.dump(obj, f, protocol=protocol)
# 
# def get_hashesperblock(blockheight):
#     '''Get the expected number of hashes required per block.'''
#     block = proxy.getblock(proxy.getblockhash(blockheight))
#     nbits = hex(block.nBits)[2:]
#     assert len(nbits) == 8
#     significand = int(nbits[2:], base=16)
#     exponent = (int(nbits[:2], base=16)-3)*8
#     logtarget = log(significand, 2) + exponent
# 
#     # This is not technically correct because the target is fulfilled in the
#     # case of equality. It should more correctly be:
#     # 2**256 / (2**logtarget + 1),
#     # but of course the difference is negligible.
#     return 2**(256 - logtarget)
# 
# Path: feemodel/app/pools.py
# class PoolsOnlineEstimator(object):
# 
#     def __init__(self, currheight, stopflag, window,
#                  minblocks=DEFAULT_MINBLOCKS):
#         self.window = window
#         self.minblocks = minblocks
#         self.poolsestimate = None
#         self.loadingthread = threading.Thread(target=self.load_estimates,
#                                               args=(currheight, stopflag))
#         self.loadingthread.start()
# 
#     def update(self, memblocks):
#         poolsestimate = copy(self.poolsestimate)
#         if poolsestimate is None:
#             # Loading is not yet finished.
#             # We just discard these blocks. Not ideal but doesn't change much.
#             return
#         for memblock in memblocks:
#             if memblock is not None:
#                 poolsestimate.update(memblock, windowsize=self.window)
#         self.check_minblocks(poolsestimate)
#         self.poolsestimate = poolsestimate
#         self.save_estimates()
# 
#     def get_pools(self):
#         # We use a getter for the pool estimate as a reminder that the
#         # reference is subject to change by the update method, so you
#         # should bind it to another variable if you want to perform multiple
#         # operations on the object.
#         return self.poolsestimate
# 
#     def save_estimates(self):
#         try:
#             save_obj(self.poolsestimate, SAVEFILE)
#         except Exception:
#             logger.warning("Unable to save pools.")
# 
#     @logexceptions
#     def load_estimates(self, currheight, stopflag):
#         try:
#             poolsestimate = load_obj(SAVEFILE)
#         except Exception:
#             logger.warning("Unable to load pool estimates; "
#                            "starting from scratch.")
#             poolsestimate = PoolsEstimatorNP()
#         startheight = currheight - self.window + 1
#         blockrangetuple = (startheight, currheight+1)
#         poolsestimate.start(blockrangetuple, stopflag=stopflag)
#         self.check_minblocks(poolsestimate)
#         self.poolsestimate = poolsestimate
# 
#     def check_minblocks(self, poolsestimate):
#         if len(poolsestimate.blockstats) < self.minblocks:
#             # Ensure that not bool(poolsestimate), using the object's
#             # __nonzero__ magic method.
#             # This is to signal to the simulator that the estimate is
#             # not ready.
#             poolsestimate.blockrate = None
# 
#     def get_stats(self):
#         stats = {
#             "params": {"window": self.window,
#                        "minblocks": self.minblocks},
#         }
#         est = self.poolsestimate
#         if not est:
#             return stats
#         # minfeerates = sorted(est.minfeerates)
#         # maxblocksizes = sorted(est.maxblocksizes)
#         capfn = est.get_capacityfn()
#         feerates, caps = zip(*capfn)
#         stats.update({
#             "feerates": feerates,
#             "caps": caps,
#             "blockinterval": 1 / est.blockrate
#         })
#         return stats
# 
#     def __nonzero__(self):
#         # TODO: Deprecate this
#         raise NotImplementedError
# 
# SAVEFILE = os.path.join(datadir, 'pools.pickle')


import unittest
import threading
from time import sleep, time
from feemodel.tests.config import mk_tmpdatadir, rm_tmpdatadir, poolsref
from feemodel.tests.pseudoproxy import install
from feemodel.util import save_obj, get_hashesperblock
from feemodel.app.pools import PoolsOnlineEstimator, SAVEFILE as pools_savefile
        print("Test B:")
        # Test loading of saved pools
        poolsref.timestamp = time()
        save_obj(poolsref, pools_savefile)
        poolsonline = PoolsOnlineEstimator(2016, update_period=1,
                                           minblocks=1)
        self.assertTrue(poolsonline)
        sleep(1)
        stopflag = threading.Event()
        t = poolsonline.update_async(333953, stopflag=stopflag)
        threading.Timer(1, stopflag.set).start()
        # next_update should be reached by now
        self.assertIsNotNone(t)
        poolsonline.poolsestimate.pools = {}
        # test stopping
        t.join()
        self.assertFalse(poolsonline)

        # test that we keep blocksmetadata even if pools are outdated
        poolsonline = PoolsOnlineEstimator(2016, update_period=0,
                                           minblocks=1)
        self.assertFalse(poolsonline)
        self.assertTrue(poolsonline.get_pools().blocksmetadata)
        t = poolsonline.update_async(333953)
        self.assertIsNotNone(t)
        t.join()
        self.assertTrue(poolsonline)

    def test_C(self):
        print("Test C:")

# Path: feemodel/tests/config.py
# def tmpdatadir_context():
# def load_obj(filename):
# def mk_tmpdatadir():
# def rm_tmpdatadir():
#     README = ("This is a temporary directory for feemodel unit tests,\n"
#               "and is meant to be removed after every test. Feel free\n"
#               "to delete it if it failed to be removed.\n")
# 
# Path: feemodel/tests/pseudoproxy.py
# def install():
#     '''Substitutes the real proxy with our pseudo one.'''
#     feemodel.util.proxy = proxy
#     feemodel.txmempool.proxy = proxy
# 
# Path: feemodel/util.py
# def save_obj(obj, filename, protocol=2):
#     '''Convenience function to pickle an object to disk.'''
#     with open(filename, 'wb') as f:
#         pickle.dump(obj, f, protocol=protocol)
# 
# def get_hashesperblock(blockheight):
#     '''Get the expected number of hashes required per block.'''
#     block = proxy.getblock(proxy.getblockhash(blockheight))
#     nbits = hex(block.nBits)[2:]
#     assert len(nbits) == 8
#     significand = int(nbits[2:], base=16)
#     exponent = (int(nbits[:2], base=16)-3)*8
#     logtarget = log(significand, 2) + exponent
# 
#     # This is not technically correct because the target is fulfilled in the
#     # case of equality. It should more correctly be:
#     # 2**256 / (2**logtarget + 1),
#     # but of course the difference is negligible.
#     return 2**(256 - logtarget)
# 
# Path: feemodel/app/pools.py
# class PoolsOnlineEstimator(object):
# 
#     def __init__(self, currheight, stopflag, window,
#                  minblocks=DEFAULT_MINBLOCKS):
#         self.window = window
#         self.minblocks = minblocks
#         self.poolsestimate = None
#         self.loadingthread = threading.Thread(target=self.load_estimates,
#                                               args=(currheight, stopflag))
#         self.loadingthread.start()
# 
#     def update(self, memblocks):
#         poolsestimate = copy(self.poolsestimate)
#         if poolsestimate is None:
#             # Loading is not yet finished.
#             # We just discard these blocks. Not ideal but doesn't change much.
#             return
#         for memblock in memblocks:
#             if memblock is not None:
#                 poolsestimate.update(memblock, windowsize=self.window)
#         self.check_minblocks(poolsestimate)
#         self.poolsestimate = poolsestimate
#         self.save_estimates()
# 
#     def get_pools(self):
#         # We use a getter for the pool estimate as a reminder that the
#         # reference is subject to change by the update method, so you
#         # should bind it to another variable if you want to perform multiple
#         # operations on the object.
#         return self.poolsestimate
# 
#     def save_estimates(self):
#         try:
#             save_obj(self.poolsestimate, SAVEFILE)
#         except Exception:
#             logger.warning("Unable to save pools.")
# 
#     @logexceptions
#     def load_estimates(self, currheight, stopflag):
#         try:
#             poolsestimate = load_obj(SAVEFILE)
#         except Exception:
#             logger.warning("Unable to load pool estimates; "
#                            "starting from scratch.")
#             poolsestimate = PoolsEstimatorNP()
#         startheight = currheight - self.window + 1
#         blockrangetuple = (startheight, currheight+1)
#         poolsestimate.start(blockrangetuple, stopflag=stopflag)
#         self.check_minblocks(poolsestimate)
#         self.poolsestimate = poolsestimate
# 
#     def check_minblocks(self, poolsestimate):
#         if len(poolsestimate.blockstats) < self.minblocks:
#             # Ensure that not bool(poolsestimate), using the object's
#             # __nonzero__ magic method.
#             # This is to signal to the simulator that the estimate is
#             # not ready.
#             poolsestimate.blockrate = None
# 
#     def get_stats(self):
#         stats = {
#             "params": {"window": self.window,
#                        "minblocks": self.minblocks},
#         }
#         est = self.poolsestimate
#         if not est:
#             return stats
#         # minfeerates = sorted(est.minfeerates)
#         # maxblocksizes = sorted(est.maxblocksizes)
#         capfn = est.get_capacityfn()
#         feerates, caps = zip(*capfn)
#         stats.update({
#             "feerates": feerates,
#             "caps": caps,
#             "blockinterval": 1 / est.blockrate
#         })
#         return stats
# 
#     def __nonzero__(self):
#         # TODO: Deprecate this
#         raise NotImplementedError
# 
# SAVEFILE = os.path.join(datadir, 'pools.pickle')


# Path: feemodel/tests/test_poolsapp.py
import unittest
import threading
from time import sleep, time
from feemodel.tests.config import mk_tmpdatadir, rm_tmpdatadir, poolsref
from feemodel.tests.pseudoproxy import install
from feemodel.util import save_obj, get_hashesperblock
from feemodel.app.pools import PoolsOnlineEstimator, SAVEFILE as pools_savefile

        print("Test B:")
        # Test loading of saved pools
        poolsref.timestamp = time()
        save_obj(poolsref, pools_savefile)
        poolsonline = PoolsOnlineEstimator(2016, update_period=1,
                                           minblocks=1)
        self.assertTrue(poolsonline)
        sleep(1)
        stopflag = threading.Event()
        t = poolsonline.update_async(333953, stopflag=stopflag)
        threading.Timer(1, stopflag.set).start()
        # next_update should be reached by now
        self.assertIsNotNone(t)
        poolsonline.poolsestimate.pools = {}
        # test stopping
        t.join()
        self.assertFalse(poolsonline)

        # test that we keep blocksmetadata even if pools are outdated
        poolsonline = PoolsOnlineEstimator(2016, update_period=0,
                                           minblocks=1)
        self.assertFalse(poolsonline)
        self.assertTrue(poolsonline.get_pools().blocksmetadata)
        t = poolsonline.update_async(333953)
        self.assertIsNotNone(t)
        t.join()
        self.assertTrue(poolsonline)

    def test_C(self):
        print("Test C:")

        poolsref.timestamp = time() - 1