tfee estimates: use median if auto-connect - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 133d74adfb4f5d0401caf50943473b129784b8ae
 (DIR) parent 5bac2fea986d27d0e2aa26fe29987e7d24233f88
 (HTM) Author: ThomasV <thomasv@electrum.org>
       Date:   Thu, 12 Mar 2020 14:38:35 +0100
       
       fee estimates: use median if auto-connect
       
       Diffstat:
         M electrum/interface.py               |      18 ++++++++++++++++++
         M electrum/network.py                 |      39 +++++++++++++++++++------------
       
       2 files changed, 42 insertions(+), 15 deletions(-)
       ---
 (DIR) diff --git a/electrum/interface.py b/electrum/interface.py
       t@@ -36,6 +36,7 @@ import itertools
        import logging
        
        import aiorpcx
       +from aiorpcx import TaskGroup
        from aiorpcx import RPCSession, Notification, NetAddress, NewlineFramer
        from aiorpcx.curio import timeout_after, TaskTimeout
        from aiorpcx.jsonrpc import JSONRPC, CodeMessageError
       t@@ -249,6 +250,7 @@ class Interface(Logger):
        
                self.tip_header = None
                self.tip = 0
       +        self.fee_estimates_eta = {}
        
                # Dump network messages (only for this interface).  Set at runtime from the console.
                self.debug = False
       t@@ -491,6 +493,7 @@ class Interface(Logger):
                    try:
                        async with self.taskgroup as group:
                            await group.spawn(self.ping)
       +                    await group.spawn(self.request_fee_estimates)
                            await group.spawn(self.run_fetch_blocks)
                            await group.spawn(self.monitor_connection)
                    except aiorpcx.jsonrpc.RPCError as e:
       t@@ -511,6 +514,21 @@ class Interface(Logger):
                    await asyncio.sleep(300)
                    await self.session.send_request('server.ping')
        
       +    async def request_fee_estimates(self):
       +        from .simple_config import FEE_ETA_TARGETS
       +        from .bitcoin import COIN
       +        while True:
       +            async with TaskGroup() as group:
       +                fee_tasks = []
       +                for i in FEE_ETA_TARGETS:
       +                    fee_tasks.append((i, await group.spawn(self.session.send_request('blockchain.estimatefee', [i]))))
       +            for nblock_target, task in fee_tasks:
       +                fee = int(task.result() * COIN)
       +                if fee < 0: continue
       +                self.fee_estimates_eta[nblock_target] = fee
       +            self.network.update_fee_estimates()
       +            await asyncio.sleep(60)
       +
            async def close(self):
                if self.session:
                    await self.session.close()
 (DIR) diff --git a/electrum/network.py b/electrum/network.py
       t@@ -458,24 +458,11 @@ class Network(Logger):
        
            async def _request_fee_estimates(self, interface):
                session = interface.session
       -        from .simple_config import FEE_ETA_TARGETS
                self.config.requested_fee_estimates()
       -        async with TaskGroup() as group:
       -            histogram_task = await group.spawn(session.send_request('mempool.get_fee_histogram'))
       -            fee_tasks = []
       -            for i in FEE_ETA_TARGETS:
       -                fee_tasks.append((i, await group.spawn(session.send_request('blockchain.estimatefee', [i]))))
       -        self.config.mempool_fees = histogram = histogram_task.result()
       +        histogram = await session.send_request('mempool.get_fee_histogram')
       +        self.config.mempool_fees = histogram
                self.logger.info(f'fee_histogram {histogram}')
                self.notify('fee_histogram')
       -        fee_estimates_eta = {}
       -        for nblock_target, task in fee_tasks:
       -            fee = int(task.result() * COIN)
       -            fee_estimates_eta[nblock_target] = fee
       -            if fee < 0: continue
       -            self.config.update_fee_estimates(nblock_target, fee)
       -        self.logger.info(f'fee_estimates {fee_estimates_eta}')
       -        self.notify('fee')
        
            def get_status_value(self, key):
                if key == 'status':
       t@@ -516,6 +503,28 @@ class Network(Logger):
                with self.interfaces_lock:
                    return list(self.interfaces)
        
       +    def get_fee_estimates(self):
       +        from statistics import median
       +        from .simple_config import FEE_ETA_TARGETS
       +        if self.auto_connect:
       +            with self.interfaces_lock:
       +                out = {}
       +                for n in FEE_ETA_TARGETS:
       +                    try:
       +                        out[n] = int(median(filter(None, [i.fee_estimates_eta.get(n) for i in self.interfaces.values()])))
       +                    except:
       +                        continue
       +                return out
       +        else:
       +            return self.interface.fee_estimates_eta
       +
       +    def update_fee_estimates(self):
       +        e = self.get_fee_estimates()
       +        for nblock_target, fee in e.items():
       +            self.config.update_fee_estimates(nblock_target, fee)
       +        self.logger.info(f'fee_estimates {e}')
       +        self.notify('fee')
       +
            @with_recent_servers_lock
            def get_servers(self):
                # note: order of sources when adding servers here is crucial!