Example #1
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('txid')
    parser.add_argument('--dev', action='store_true')
    parser.add_argument('--networkid')
    parser.add_argument('--port')
    args = parser.parse_args()

    if args.dev:
        d = daemon.Daemon(port=args.port,
                          cookie_dir=f'~/.tapyrus/dev-{args.networkid}')
    else:
        d = daemon.Daemon(port=args.port,
                          cookie_dir=f'~/.tapyrus/prod-{args.networkid}')

    txid = args.txid

    txn, = d.request('getrawtransaction', [[txid, True]])
    vin = txn['vin']

    fee = 0.0
    for txi in txn['vin']:
        prev_txid = txi['txid']
        prev_tx, = d.request('getrawtransaction', [[prev_txid, True]])
        index = txi['vout']
        prev_txo = prev_tx['vout'][index]
        print(f"{prev_txid}:{index:<5} {prev_txo['value']:+20.8f}")
        fee += prev_txo['value']

    for i, txo in enumerate(txn['vout']):
        print(f"{txid}:{i:<5} {-txo['value']:+20.8f}")
        fee -= txo['value']

    print(
        f"Fee = {1e6 * fee:.2f} uBTC = {1e8 * fee / txn['vsize']:.2f} sat/vB")
Example #2
0
    def __init__(self, profile_name=None):
        storage_provider = storage.PickleProvider()
        storage_factory = storage.Factory(storage_provider)

        monitors_repository = monitors.Repository()
        hardware_inventory = hardware.Inventory()
        device_matcher = hardware.DeviceMatcher()
        plugin_instance_factory = plugins.instance.Factory()

        plugins_repository = plugins.Repository(monitors_repository,
                                                storage_factory,
                                                hardware_inventory,
                                                device_matcher,
                                                plugin_instance_factory)
        unit_manager = units.Manager(plugins_repository, monitors_repository)

        profile_factory = profiles.Factory()
        profile_merger = profiles.Merger()
        profile_locator = profiles.Locator(consts.LOAD_DIRECTORIES)
        profile_loader = profiles.Loader(profile_locator, profile_factory,
                                         profile_merger)

        self._daemon = daemon.Daemon(unit_manager, profile_loader,
                                     profile_name)
        self._controller = controller.Controller(self._daemon)

        self._dbus_exporter = None
        self._init_signals()

        self._pid_file = None
Example #3
0
	def __init__(self, profile_name = None, config = None):
		self._dbus_exporter = None

		storage_provider = storage.PickleProvider()
		storage_factory = storage.Factory(storage_provider)

		monitors_repository = monitors.Repository()
		hardware_inventory = hardware.Inventory()
		device_matcher = hardware.DeviceMatcher()
		device_matcher_udev = hardware.DeviceMatcherUdev()
		plugin_instance_factory = plugins.instance.Factory()
		self.variables = profiles.variables.Variables()

		self.config = GlobalConfig() if config is None else config
		if self.config.get_bool(consts.CFG_DYNAMIC_TUNING):
			log.info("dynamic tuning is enabled (can be overriden in plugins)")
		else:
			log.info("dynamic tuning is globally disabled")

		plugins_repository = plugins.Repository(monitors_repository, storage_factory, hardware_inventory,\
			device_matcher, device_matcher_udev, plugin_instance_factory, self.config, self.variables)
		def_instance_priority = int(self.config.get(consts.CFG_DEFAULT_INSTANCE_PRIORITY, consts.CFG_DEF_DEFAULT_INSTANCE_PRIORITY))
		unit_manager = units.Manager(plugins_repository, monitors_repository, def_instance_priority)

		profile_factory = profiles.Factory()
		profile_merger = profiles.Merger()
		profile_locator = profiles.Locator(consts.LOAD_DIRECTORIES)
		profile_loader = profiles.Loader(profile_locator, profile_factory, profile_merger, self.config, self.variables)

		self._daemon = daemon.Daemon(unit_manager, profile_loader, profile_name, self.config, self)
		self._controller = controller.Controller(self._daemon, self.config)

		self._init_signals()

		self._pid_file = None
Example #4
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('txid')
    args = parser.parse_args()

    d = daemon.Daemon(port=1441, cookie_dir='~/.groestlcoin')
    txid = args.txid

    txn, = d.request('getrawtransaction', [[txid, True]])
    vin = txn['vin']

    fee = 0.0
    for txi in txn['vin']:
        prev_txid = txi['txid']
        prev_tx, = d.request('getrawtransaction', [[prev_txid, True]])
        index = txi['vout']
        prev_txo = prev_tx['vout'][index]
        print(f"{prev_txid}:{index:<5} {prev_txo['value']:+20.8f}")
        fee += prev_txo['value']

    for i, txo in enumerate(txn['vout']):
        print(f"{txid}:{i:<5} {-txo['value']:+20.8f}")
        fee -= txo['value']

    print(
        f"Fee = {1e6 * fee:.2f} uBTC = {1e8 * fee / txn['vsize']:.2f} sat/vB")
Example #5
0
def main():
    possible_actions = ['start', 'stop', 'status', 'reload']

    arguments.parse_args(possible_actions)
    arguments.setup_logging()

    if CONF.action is None or CONF.action not in possible_actions:
        CONF.print_help()
        return 65  # os.EX_DATAERR

    apiclient = None
    if CONF.no_api is False:
        try:
            apiclient = client.Client(opts=CONF)
            if CONF.client_id:
                apiclient.client_id = CONF.client_id
        except Exception as e:
            LOG.error(e)
            print(e)
            sys.exit(1)
    else:
        if winutils.is_windows():
            print("--no-api mode is not available on windows")
            return 69  # os.EX_UNAVAILABLE

    freezer_utils.create_dir(CONF.jobs_dir, do_log=False)
    freezer_scheduler = FreezerScheduler(apiclient=apiclient,
                                         interval=int(CONF.interval),
                                         job_path=CONF.jobs_dir,
                                         concurrent_jobs=CONF.concurrent_jobs)

    if CONF.no_daemon:
        print('Freezer Scheduler running in no-daemon mode')
        LOG.debug('Freezer Scheduler running in no-daemon mode')
        if winutils.is_windows():
            daemon = win_daemon.NoDaemon(daemonizable=freezer_scheduler)
        else:
            daemon = linux_daemon.NoDaemon(daemonizable=freezer_scheduler)
    else:
        if winutils.is_windows():
            daemon = win_daemon.Daemon(daemonizable=freezer_scheduler,
                                       interval=int(CONF.interval),
                                       job_path=CONF.jobs_dir,
                                       insecure=CONF.insecure,
                                       concurrent_jobs=CONF.concurrent_jobs)
        else:
            daemon = linux_daemon.Daemon(daemonizable=freezer_scheduler)

    if CONF.action == 'start':
        daemon.start()
    elif CONF.action == 'stop':
        daemon.stop()
    elif CONF.action == 'reload':
        daemon.reload()
    elif CONF.action == 'status':
        daemon.status()

    # os.RETURN_CODES are only available to posix like systems, on windows
    # we need to translate the code to an actual number which is the equivalent
    return 0  # os.EX_OK
Example #6
0
def main():
    daemon = False
    for arg in sys.argv:
        if re.match('-d', arg) or re.match('--daemon', arg):
            daemon = True
    if daemon:
        myDaemon = Daemon.Daemon('/tmp/oshirase.pid')
        myDaemon.start()
    else:
        task.runTask()
Example #7
0
def listdomain(domain, password):
    conn = daemon.Daemon()
    response = conn.execute(daemon.Command('listdomain', (domain, password)))
    users = []
    while 1:
        r = conn.read_response()
        if not r:
            break
        (username, data) = string.split(r, '\0', 1)
        users.append(types.NamedVUser(username, types.VUser(data)))
    return users
Example #8
0
def create_date_x_days_in_past(
        n):  # so many days in the past from today's date
    return datetime.date.fromordinal(datetime.date.today().toordinal() - n)


BULK_BILL_WAITING = 4003  #magic code belonging to Ian which he made up means invoices waiting to be uploaded for bulk billing
PRIVATE_WAITING = 4005  #magic code belonging to Ian which he made up means a private invoice waiting to upload

if len(sys.argv) > 1:
    match = sys.argv[1]
else:
    match = "*"

match = match.replace('.', '_')
d = daemon.Daemon()
d.setup_test()

fmt = logging.Formatter(fmt='%(asctime)s\t%(levelname)s\t%(message)s')

if match == "reports":
    # grab a whole bunch of processing reports and print them
    for line in sys.stdin.readlines():
        m = re.match("^([0-9]+\\.[0-9]+\\.[0-9]+)", line)
        if m:
            test_name = m.group(1)
        m = re.match("^Claim ID: ([A-Z][0-9]+.*)", line)
        if m:
            claim_id = m.group(1)
            print "\n\n\n**** Bulk-billing processing report for test {} claim ID {}".format(
                test_name, claim_id)
Example #9
0
def start_daemon(edge):
    d = daemon.Daemon(edge.host, edge.port, edge.command)
    logg('Starting daemon with the following command:\n%s' % edge.command)
    d.start()
                factor = start_price / end_price - 1.
                change = float(started_bet.stake) * factor
                transaction_return = sfapp.Transaction(
                    userid=started_bet.userid,
                    amount=started_bet.stake,
                    date=datetime.datetime.utcnow(),
                    description=sfapp.Transaction.BET_SETTLE_RETURN_STAKE,
                )
                transaction_change = sfapp.Transaction(
                    userid=started_bet.userid,
                    amount=change,
                    date=datetime.datetime.utcnow(),
                    description=sfapp.Transaction.BET_SETTLE_YIELD,
                )
                sfapp_sess.add(transaction_return)
                sfapp_sess.add(transaction_change)

    LOGGER.info('End: started_to_settled')


if __name__ == '__main__':

    daemon = daemon.Daemon(logpath=os.path.join(ROOT_DIR,
                                                sys.argv[0] + '.log'),
                           update_interval_seconds=10.,
                           f=started_to_settled,
                           level=logging.DEBUG,
                           also_log_to_stderr=1)

    daemon.start()
Example #11
0
    def handle(self, *args, **options):
        # pylint: disable=too-many-locals
        # gevent monkey patch
        # Note: after patch, gevent-fastcgi will spawn new greenlet for each request,
        # which means django models will create new connection for each request.
        # it is suggested to use gunicorn instead of gevent-fastcgi in gevent mode.
        if options['monkey_patch']:
            names = filter(None,
                           map(str.strip, options['monkey_patch'].split(',')))
            if names:
                module = __import__('gevent.monkey', fromlist=['*'])
                for name in names:
                    if name not in MONKEY_PATCH_NAMES:
                        raise CommandError(
                            'Unknown name "{0}" in --monkey-patch option'.
                            format(name))
                    patch_func = getattr(module, 'patch_{0}'.format(name))
                    patch_func()

            # replace MySQLdb with pymysql for gevent
            import pymysql
            pymysql.install_as_MySQLdb()

        import os
        import sys
        from os.path import dirname, isdir

        # patch python2.6 logging module
        if sys.version_info < (2, 7):
            import logging

            class NullHandler(logging.Handler):
                def emit(self, record):
                    pass

            logging.NullHandler = NullHandler

        # patch gevent fastcgi for werkzeug / flask
        from gevent_fastcgi.base import InputStream

        def readline(self, size=-1):
            self._eof_received.wait()
            return self._file.readline(size)

        InputStream.readline = readline

        from gevent_fastcgi.wsgi import WSGIRequest
        from gevent_fastcgi.interfaces import IRequestHandler
        from zope.interface import implements
        from gevent_fastcgi.server import FastCGIServer

        class WSGIRequestHandler(object):

            implements(IRequestHandler)

            def __init__(self, app):
                self.app = app

            def __call__(self, fastcgi_request):
                # pylint: disable=protected-access
                request = WSGIRequest(fastcgi_request)
                try:
                    app_iter = self.app(request._environ,
                                        request.start_response)
                    request.finish(app_iter)
                    if hasattr(app_iter, 'close'):
                        app_iter.close()
                except:
                    try:
                        from logger import log
                        logging.exception('handle_http_request_exception')
                    except:
                        pass
                    request.start_response('500 Internal Server Error', [
                        ('Content-type', 'text/plain'),
                    ])
                    request.finish(['Internal Server Error (500)'])

        # subclass gevent fastcgi so each spawned process has distinctive random seeds
        class GFastCGIServer(FastCGIServer):
            def start_accepting(self):
                import random
                random.seed()
                return super(GFastCGIServer, self).start_accepting()

        if not args:
            raise CommandError('Please specify binding address')

        if len(args) > 1:
            raise CommandError('Unexpected arguments: %s' % ' '.join(args[1:]))

        bind_address = args[0]

        try:
            host, port = bind_address.split(':', 1)
            port = int(port)
        except ValueError:
            socket_dir = dirname(bind_address)
            if not isdir(socket_dir):
                raise CommandError(
                    'Please create directory for socket file first %r' %
                    dirname(socket_dir))
        else:
            if options['socket_mode'] is not None:
                raise CommandError('--socket-mode option can only be used '
                                   'with Unix domain sockets. Either use '
                                   'socket file path as address or do not '
                                   'specify --socket-mode option')
            bind_address = (host, port)

        pid_file = options.get('daemon')
        if pid_file:
            import daemon
            daemon = daemon.Daemon(None, pid_file,
                                   options.get('out_log', '/dev/null'))
            daemon.start()

        kwargs = dict(((name, value) for name, value in options.iteritems()
                       if name in ('num_workers', 'max_conns', 'buffer_size',
                                   'socket_mode')))

        os.chdir(options['our_home_dir'])
        if options['our_home_dir'] not in sys.path:
            sys.path.append(options['our_home_dir'])

        wsgi_args = options['wsgi'].split(':')
        wsgi_module = wsgi_args[0]
        if len(wsgi_args) > 1:
            wsgi_object = wsgi_args[1]
        else:
            wsgi_object = 'app'

        app_module = __import__(wsgi_module, fromlist=[wsgi_object])
        app = getattr(app_module, wsgi_object)

        request_handler = WSGIRequestHandler(app)
        server = GFastCGIServer(bind_address, request_handler, **kwargs)
        server.serve_forever()
    ### rotating_file_handler = logging.handlers.RotatingFileHandler(
    ### 		os.path.join(ROOT_DIR, os.path.basename(os.path.abspath(__file__)) + '.log'),
    ### 		maxBytes = 10 * 1024 * 1024,
    ### 		backupCount = 2,
    ### 		encoding = 'utf-8'
    ### )
    ### rotating_file_handler.setFormatter(formatter)
    ### rotating_file_handler.setLevel(logging.DEBUG)
    ### if ALSO_TO_STDERR:
    ### 	ROOT_LOGGER.addHandler(stream_handler)
    ### ROOT_LOGGER.addHandler(rotating_file_handler)
    downloader = Downloader(UPDATE_INTERVAL)
    ### try:
    ### 	downloader.start()
    ### except Exception as exc:
    ### 	LOGGER.exception('Unhandled exception: \n%s', exc)
    ### 	raise

    daemon = daemon.Daemon(
        logpath=os.path.join(
            ROOT_DIR,
            os.path.basename(os.path.abspath(__file__)) + '.log'),
        update_interval_seconds=UPDATE_INTERVAL,
        f=downloader.start,
        also_log_to_stderr=ALSO_TO_STDERR,
        level=logging.DEBUG,
        lockid='pinnacle_download',
    )

    daemon.start()
Example #13
0
import daemon

if __name__ == '__main__':

    help = "please select between those actions: \n\n -start: launch the daemon \n -stop: stop it \n -restart: restart it \n -pause: stop all devices but doesn't stop the daemon until play \n -play: returning the daemon to his normal behaviour after a pause \n"

    if len(sys.argv) > 1:
        action = sys.argv[1]
    else:
        action = None

    logfile = os.path.join(os.getcwd(), "daemon.log")
    pidfile = os.path.join(os.getcwd(), "daemon.pid")

    logging.basicConfig(filename=logfile, level=logging.DEBUG)
    d = daemon.Daemon(pidfile=pidfile)

    if action == "start":

        d.start()

    elif action == "stop":

        d.stop()

    elif action == "restart":

        d.restart()

    elif action == "pause":
Example #14
0
def init(basename, configDefaults=None, configItems=None):
    global _daemon

    cwd = os.path.abspath(os.getcwd())
    home = os.path.expanduser('~')

    _configDefaults = {
        'basename': basename,
        'daemon': False,
        'pidpath': cwd,
        'logpath': cwd,
        'uid': None,
        'console': True,
        'debug': True,
        'rmqServer': None,
        'rmqUser': '******',
        'rmqPassword': None,
        'rmqConfig': None,
    }

    palalaConfig = os.path.join(cwd, 'palala.cfg')

    if os.path.isfile(palalaConfig):
        for line in open(palalaConfig, 'r').readlines():
            if not line.startswith('#'):
                item = line[:-1].split('=')
                if len(item) == 2:
                    _configDefaults[item[0]] = item[1]

    if configDefaults is not None:
        for key in configDefaults:
            _configDefaults[key] = configDefaults[key]

    _configItems = {
        'basename':
        ('', '--name', _configDefaults['basename'], 'Name of the bot'),
        'daemon':
        ('', '--daemon', _configDefaults['daemon'], 'run as a daemon', 'b'),
        'pidpath':
        ('', '--pidpath', _configDefaults['pidpath'], 'pid file path'),
        'logpath':
        ('', '--logpath', _configDefaults['logpath'], 'log file path'),
        'uid': ('', '--uid', _configDefaults['uid'], 'uid to run as'),
        'console': ('-e', '--echo', _configDefaults['console'],
                    'echo to console', 'b'),
        'debug': ('-d', '--debug', _configDefaults['debug'],
                  'turn on debug messages', 'b'),
        'rmqServer': ('', '--rmqserver', _configDefaults['rmqServer'],
                      'Hostname for RMQ Server'),
        'rmqUser': ('', '--rmquser', _configDefaults['rmqUser'],
                    'Username to login to RMQ Server'),
        'rmqPassword': ('', '--rmqpw', _configDefaults['rmqPassword'],
                        'User password for RMQ Server'),
        'rmqConfig': ('', '--rmqconfig', _configDefaults['rmqConfig'],
                      'Queue Config file for RMQ Server'),
    }

    if configItems is not None:
        for key in configItems:
            _configItems[key] = configItems[key]

    if 'config' not in _configItems:
        s = os.path.join(home, 'etc', '%s.cfg' % _configDefaults['basename'])
        _configItems['config'] = (
            '-c',
            '--config',
            s,
            'Configuration file to load',
        )

    initOptions(_configItems)
    initLogging()

    if options.daemon:
        try:
            _daemon = daemon.Daemon(pidfile=options.pidfile,
                                    user=options.uid,
                                    sigterm=handle_sigterm,
                                    log=log.fileHandler)
        except:
            utils.dumpException('exception setting up daemon')
            sys.exit(1)

        log.info('forking daemon - pidfile is %s' % options.pidfile)
        _daemon.start()

    log.info('%s starting' % options.basename)
Example #15
0
def unconfirmed(provider):
    num_outs = {}
    num_ins = {}
    fees = []
    feesperkb = []
    population_max_in_fraction_all = []
    thresh750 = 0.0
    thresh1000 = 0.0
    est1 = 0
    est6 = 0
    est12 = 0
    est24 = 0

    def get_stats(data):
        if len(data) > 0:
            arr = numpy.array(data)
            return (numpy.mean(arr), numpy.std(arr))
        return "No data"

    def get_fee_stats(data):
        if len(data) > 0:
            arr = numpy.array(data)
            print ""
            print "All fees in mBTC"
            print "Bitcoinexchangerate.org Fee Estimates --------"
            print "Minimum fee/KB for 750KB block: " + str(thresh750)
            print "Minimum fee/KB for 1MB block: " + str(thresh1000)
            print ""
            print "Bitcoin Core Fee Estimates -------------------"
            print "Blocks ---- mBTC/KB"
            print "     1      " + str(float(est1) * 1000.0)
            print "     6      " + str(float(est6) * 1000.0)
            print "    12      " + str(float(est12) * 1000.0)
            print "    24      " + str(float(est24) * 1000.0)
            print ""
            print "Statistics -----------------------------------"
            print "Minimum fee: " + str(numpy.min(arr) / 100000.0)
            print "Maximum fee: " + str(numpy.max(arr) / 100000.0)
            print "Average fee for payers: " + str(numpy.mean(arr) / 100000.0)
            print "Median fee for payers: " + str(numpy.median(arr) / 100000.0)
            print "Stdev of fee for payers: " + str(numpy.std(arr) / 100000.0)
        return "No data"

    def jsonify(data):
        if len(data) > 0:
            arr = numpy.array(data)
            j = {
                "result": "success",
                "min_for_750k": str(thresh750),
                "min_for_1000k": str(thresh1000),
                "core_est_1": str(float(est1) * 1000.0),
                "core_est_6": str(float(est6) * 1000.0),
                "core_est_12": str(float(est12) * 1000.0),
                "core_est_24": str(float(est24) * 1000.0),
                "mempool_min_fee": str(numpy.min(arr) / 100000.0),
                "mempool_max fee": str(numpy.max(arr) / 100000.0),
                "mempool_avg_nonzero_fee": str(numpy.mean(arr) / 100000.0),
                "mempool_median_nonzero_fee":
                str(numpy.median(arr) / 100000.0),
                "mempool_stdev_nonzero_fee": str(numpy.std(arr) / 100000.0),
            }
        else:
            j = {"result": "error"}
        return json.dumps(j)

    raw = ''
    txs = []
    data = {}
    if provider == 'blockchain':
        url = "https://blockchain.info/unconfirmed-transactions?format=json&offset="

        response = urllib.urlopen("https://blockchain.info/q/unconfirmedcount")
        unconf_count = int(response.read())
        print "Getting " + str(unconf_count) + " unconfirmed transactions."
        for i in range(unconf_count, 0, -50):
            #for i in range(0,50,50):
            #print i
            response = urllib.urlopen(url + str(i))
            raw = response.read()
            #print raw[0:100]
            parsed = json.loads(raw)
            txs = txs + parsed[u'txs']

        height = "unconf"
        block_hash = "unconf"
        data[u'tx'] = txs

    elif provider == 'bitcoind':
        d = daemon.Daemon()
        raw = d.get_rawmempool()
        #txs = json.loads(raw)
        data[u'tx'] = raw

        est1 = d.get_estimatefee(1)
        est6 = d.get_estimatefee(6)
        est12 = d.get_estimatefee(12)
        est24 = d.get_estimatefee(24)

        # u'6d2b502eea0f8575d84eba792d811f5bb80dbeb92083111a4a8a5f500d75b788':
        # {
        #  u'fee': 0.0001,
        #  u'startingpriority': 8459910.32051282,
        #  u'height': 362735,
        #  u'depends': [],
        #  u'time': 1435380798,
        #  u'currentpriority': 8459910.32051282,
        #  u'size': 226
        # }

    total_tx = 0
    has_fee = 0
    prev_out_txindex = []
    if provider == 'blockchain':
        for tx in data[u'tx']:
            total_value = 0
            num_out = 0
            max_value = 0

            total_in_value = 0
            num_in = 0
            max_in_value = 0
            for output in tx[u'out']:
                total_value = total_value + output[u'value']
                if output[u'value'] > max_value:
                    max_value = output[u'value']
                num_out = num_out + 1

            for prev in tx[u'inputs']:
                if 'prev_out' in prev:
                    prev_out_txindex.append(prev['prev_out']['tx_index'])
                    in_value = prev['prev_out']['value']
                    total_in_value = total_in_value + in_value
                    if in_value > max_in_value:
                        max_in_value = in_value
                    num_in = num_in + 1

            fee = total_in_value - total_value
            if fee > 0:
                has_fee += 1

            if num_in > 0:
                fees.append(fee)
                size = tx['size'] / 1000.0
                feesperkb.append([fee / size / 100000.0, tx['size']])

            total_tx += 1

            if num_out in num_outs.keys():
                num_outs[num_out] = num_outs[num_out] + 1
            else:
                num_outs[num_out] = 1

            if num_in in num_ins.keys():
                num_ins[num_in] = num_ins[num_in] + 1
            else:
                num_ins[num_in] = 1

    elif provider == 'bitcoind':
        for txid in data[u'tx']:
            tx = data[u'tx'][txid]
            total_value = 0
            num_out = 0
            max_value = 0

            total_in_value = 0
            num_in = 0
            max_in_value = 0

            fee = tx[u'fee'] * 100000000.0
            if fee > 0:
                has_fee += 1

            fees.append(fee)
            size = tx['size'] / 1000.0
            feesperkb.append([fee / size / 100000.0, tx['size']])

            total_tx += 1

    print "Total transactions: " + str(total_tx) + "  No fee: " + str(
        total_tx - has_fee)

    # calculate minimum fee/kb for inclusion in 750KB and 1MB blocks
    # sort feesperkb by highest fees first, then create a cumulative sum of KBs at that fee or above

    feesperkb = sorted(feesperkb, key=itemgetter(0), reverse=True)
    #print str(feesperkb)

    bytessofar = 0
    bytesbyfee = {}
    for i in feesperkb:
        if i[0] in bytesbyfee:
            bytesbyfee[i[0]] += i[1]
        else:
            bytesbyfee[i[0]] = bytessofar + i[1]
        bytessofar += i[1]
        if bytessofar > 750000 and thresh750 == 0:
            thresh750 = i[0]
        if bytessofar > 1000000 and thresh1000 == 0:
            thresh1000 = i[0]

    get_fee_stats(fees)

    b = []
    f = []

    fo = open("info/bitcoin-fee-distribution.csv", "w")
    fo.write('Unconfirmed Fee Distribution\n(' +
             strftime("%a %d %b %Y %H:%M:%S", gmtime()) +
             ' UTC)\nmBTC/KB,KB\n')
    for i in sorted(bytesbyfee, reverse=True):
        b.append(bytesbyfee[i] / 1000.0)
        f.append(i)
        fo.write(str(i) + "," + str(bytesbyfee[i] / 1000.0) + "\n")
    fo.close()

    print "Total bytes: " + str(bytessofar)

    j = jsonify(fees)
    fj = open("info/bitcoin-fee-distribution.json", "w")
    fj.write(j)
    fj.close()

    x = numpy.array(f)
    y = numpy.array(b)
    plt.plot(x, y, c='blue')
    plt.xticks(numpy.arange(min(x), max(x), 0.2))
    plt.xlim(0, 2.0)
    plt.yscale('log')
    plt.title('Unconfirmed Fee Distribution\n' +
              strftime("%a %d %b %Y %H:%M:%S", gmtime()) + ' UTC')
    plt.ylabel('Transactions (KB)')
    plt.xlabel('Fee threshold (mBTC per KB)')
    plt.savefig('info/bitcoin-fee-distribution.png')