URI: 
       tdynamic fees: define fee levels using expected confirmation times - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 2cf479525043203675815341ea3fca8b83d210f4
   DIR parent 352cdd7f5ab923288b460bf6904efca82f0aaf37
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Tue, 31 May 2016 20:26:09 +0200
       
       dynamic fees: define fee levels using expected confirmation times
       
       Diffstat:
         M gui/kivy/uix/dialogs/fee_dialog.py  |      18 ++++++------------
         M gui/qt/main_window.py               |      11 ++++++-----
         M lib/network.py                      |      27 ++++++++++++++++++++++-----
         M lib/util.py                         |       2 +-
         M lib/wallet.py                       |      18 +++++++-----------
       
       5 files changed, 42 insertions(+), 34 deletions(-)
       ---
   DIR diff --git a/gui/kivy/uix/dialogs/fee_dialog.py b/gui/kivy/uix/dialogs/fee_dialog.py
       t@@ -34,14 +34,6 @@ Builder.load_string('''
                    CheckBox:
                        id: dynfees
                        on_active: root.on_checkbox(self.active)
       -        BoxLayout:
       -            orientation: 'horizontal'
       -            size_hint: 1, None
       -            Label:
       -                id: reco
       -                font_size: '6pt'
       -                text_size: self.size
       -                text: ''
                Widget:
                    size_hint: 1, 1
                BoxLayout:
       t@@ -77,9 +69,6 @@ class FeeDialog(Factory.Popup):
                self.update_slider()
                self.update_text()
        
       -        if self.app.network and self.app.network.fee:
       -            self.ids.reco.text = _('Recommended fee for inclusion in the next two blocks') + ': ' + self.app.format_amount_and_units(self.app.network.fee) +'/kb' 
       -
            def update_text(self):
                self.ids.fee_per_kb.text = self.get_fee_text()
        
       t@@ -96,7 +85,12 @@ class FeeDialog(Factory.Popup):
        
            def get_fee_text(self):
                if self.ids.dynfees.active:
       -            return fee_levels[self.fee_level] + ' (%d%%)'% (100 * (self.fee_level + 1)/3)
       +            tooltip = fee_levels[self.fee_level]
       +            if self.app.network:
       +                dynfee = self.app.network.dynfee(self.fee_level)
       +                if dynfee:
       +                    tooltip += '\n' + (self.app.format_amount_and_units(dynfee)) + '/kB'
       +            return tooltip
                else:
                    return self.app.format_amount_and_units(self.static_fee) + '/kB'
        
   DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -925,7 +925,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                def slider_moved():
                    from electrum.util import fee_levels
                    i = self.fee_slider.sliderPosition()
       -            tooltip = fee_levels[i] + ' (%d%%)'% (100 * (i + 1)/3)
       +            tooltip = fee_levels[i]
       +            dynfee = self.network.dynfee(i)
       +            if dynfee:
       +                tooltip += '\n' + self.format_amount(dynfee) + ' ' + self.base_unit() + '/kB'
                    QToolTip.showText(QCursor.pos(), tooltip, self.fee_slider)
                def slider_released():
                    self.config.set_key('fee_level', self.fee_slider.sliderPosition(), False)
       t@@ -933,7 +936,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                        self.spend_max()
                    else:
                        self.update_fee()
       -
                self.fee_slider.valueChanged.connect(slider_moved)
                self.fee_slider.sliderReleased.connect(slider_released)
                self.fee_slider.setValue(self.config.get('fee_level', 2))
       t@@ -2376,12 +2378,11 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                dynfee_cb.setToolTip(_("Use a fee per kB value recommended by the server."))
                fee_widgets.append((dynfee_cb, None))
                def update_feeperkb():
       -            fee_e.setAmount(self.wallet.fee_per_kb(self.config))
       +            fee_e.setAmount(self.config.get('fee_per_kb', bitcoin.RECOMMENDED_FEE))
                    b = self.config.get('dynamic_fees', False)
                    fee_e.setEnabled(not b)
                def on_dynfee(x):
       -            dynfee = x == Qt.Checked
       -            self.config.set_key('dynamic_fees', dynfee)
       +            self.config.set_key('dynamic_fees', x == Qt.Checked)
                    update_feeperkb()
                    self.update_fee_edit()
                dynfee_cb.stateChanged.connect(on_dynfee)
   DIR diff --git a/lib/network.py b/lib/network.py
       t@@ -42,6 +42,8 @@ from interface import Connection, Interface
        from blockchain import Blockchain
        from version import ELECTRUM_VERSION, PROTOCOL_VERSION
        
       +FEE_TARGETS = [25, 10, 5, 2]
       +
        DEFAULT_PORTS = {'t':'50001', 's':'50002', 'h':'8081', 'g':'8082'}
        
        DEFAULT_SERVERS = {
       t@@ -190,7 +192,7 @@ class Network(util.DaemonThread):
        
                self.banner = ''
                self.donation_address = ''
       -        self.fee = None
       +        self.fee_estimates = {}
                self.relay_fee = None
                self.heights = {}
                self.merkle_roots = {}
       t@@ -314,7 +316,8 @@ class Network(util.DaemonThread):
                self.queue_request('server.banner', [])
                self.queue_request('server.donation_address', [])
                self.queue_request('server.peers.subscribe', [])
       -        self.queue_request('blockchain.estimatefee', [2])
       +        for i in FEE_TARGETS:
       +            self.queue_request('blockchain.estimatefee', [i])
                self.queue_request('blockchain.relayfee', [])
        
            def get_status_value(self, key):
       t@@ -323,7 +326,7 @@ class Network(util.DaemonThread):
                elif key == 'banner':
                    value = self.banner
                elif key == 'fee':
       -            value = self.fee
       +            value = self.fee_estimates
                elif key == 'updated':
                    value = (self.get_local_height(), self.get_server_height())
                elif key == 'servers':
       t@@ -332,6 +335,20 @@ class Network(util.DaemonThread):
                    value = self.get_interfaces()
                return value
        
       +    def dynfee(self, i):
       +        from bitcoin import RECOMMENDED_FEE
       +        if i < 4:
       +            j = FEE_TARGETS[i]
       +            fee = self.fee_estimates.get(j)
       +        else:
       +            assert i == 4
       +            fee = self.fee_estimates.get(2)
       +            if fee is not None:
       +                fee += fee/2
       +        if fee is not None:
       +            fee = min(10*RECOMMENDED_FEE, fee)
       +        return fee
       +
            def notify(self, key):
                if key in ['status', 'updated']:
                    self.trigger_callback(key)
       t@@ -514,8 +531,8 @@ class Network(util.DaemonThread):
                        self.donation_address = result
                elif method == 'blockchain.estimatefee':
                    if error is None:
       -                self.fee = int(result * COIN)
       -                self.print_error("recommended fee", self.fee)
       +                i = params[0]
       +                self.fee_estimates[i] = int(result * COIN)
                        self.notify('fee')
                elif method == 'blockchain.relayfee':
                    if error is None:
   DIR diff --git a/lib/util.py b/lib/util.py
       t@@ -36,7 +36,7 @@ import threading
        from i18n import _
        
        base_units = {'BTC':8, 'mBTC':5, 'uBTC':2}
       -fee_levels = [_('Very low'), _('Low'), _('Normal'), _('High'), _('Very high')]
       +fee_levels = [_('Within 25 blocks'), _('Within 10 blocks'), _('Within 5 blocks'), _('Within 2 blocks'), _('In the next block')]
        
        def normalize_version(v):
            return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -909,15 +909,11 @@ class Abstract_Wallet(PrintError):
        
            def fee_per_kb(self, config):
                b = config.get('dynamic_fees')
       -        F = config.get('fee_per_kb', bitcoin.RECOMMENDED_FEE)
       -        if b and self.network and self.network.fee:
       -            i = config.get('fee_level', 2)
       -            fee = self.network.fee*(i+1)/3
       -            fee = max(fee, self.relayfee())
       -            fee = min(10*bitcoin.RECOMMENDED_FEE, fee)
       -            return fee
       +        i = config.get('fee_level', 2)
       +        if b and self.network and self.network.dynfee(i):
       +            return self.network.dynfee(i)
                else:
       -            return F
       +            return config.get('fee_per_kb', bitcoin.RECOMMENDED_FEE)
        
            def get_tx_status(self, tx_hash, height, conf, timestamp):
                from util import format_time
       t@@ -925,10 +921,10 @@ class Abstract_Wallet(PrintError):
                    tx = self.transactions.get(tx_hash)
                    is_final = tx and tx.is_final()
                    fee = self.tx_fees.get(tx_hash)
       -            if fee and self.network and self.network.fee:
       +            if fee and self.network and self.network.dynfee(25):
                        size = len(tx.raw)/2
       -                network_fee = int(self.network.fee * size / 1000)
       -                is_lowfee = fee < network_fee * 0.25
       +                low_fee = int(self.network.dynfee(25)*size/1000)
       +                is_lowfee = fee < low_fee * 0.5
                    else:
                        is_lowfee = False
                    if not is_final: