electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit a98e833897dc11ec7ff8c854fe512a3fc549f6c7
parent 2cc15fca578b0ee6e87c1429d8afeedc4a7e156a
Author: ghost43 <somber.night@protonmail.com>
Date:   Fri, 15 Jun 2018 17:02:44 +0200

getfeerate command: add optional parameters to specify custom fee level (#4264)


Diffstat:
Mlib/commands.py | 25+++++++++++++++++++++----
Mlib/daemon.py | 2++
Mlib/simple_config.py | 46++++++++++++++++++++++++++++++++++++----------
3 files changed, 59 insertions(+), 14 deletions(-)

diff --git a/lib/commands.py b/lib/commands.py @@ -657,10 +657,23 @@ class Commands: return self.wallet.is_up_to_date() @command('n') - def getfeerate(self): - """Return current optimal fee rate per kilobyte, according - to config settings (static/dynamic)""" - return self.config.fee_per_kb() + def getfeerate(self, fee_method=None, fee_level=None): + """Return current suggested fee rate (in sat/kvByte), according to config + settings or supplied parameters. + """ + if fee_method is None: + dyn, mempool = None, None + elif fee_method.lower() == 'static': + dyn, mempool = False, False + elif fee_method.lower() == 'eta': + dyn, mempool = True, False + elif fee_method.lower() == 'mempool': + dyn, mempool = True, True + else: + raise Exception('Invalid fee estimation method: {}'.format(fee_method)) + if fee_level is not None: + fee_level = Decimal(fee_level) + return self.config.fee_per_kb(dyn=dyn, mempool=mempool, fee_level=fee_level) @command('') def help(self): @@ -719,6 +732,8 @@ command_options = { 'show_addresses': (None, "Show input and output addresses"), 'show_fiat': (None, "Show fiat value of transactions"), 'year': (None, "Show history for a given year"), + 'fee_method': (None, "Fee estimation method to use"), + 'fee_level': (None, "Float between 0.0 and 1.0, representing fee slider position") } @@ -738,6 +753,8 @@ arg_types = { 'fee': lambda x: str(Decimal(x)) if x is not None else None, 'amount': lambda x: str(Decimal(x)) if x != '!' else '!', 'locktime': int, + 'fee_method': str, + 'fee_level': json_loads, } config_variables = { diff --git a/lib/daemon.py b/lib/daemon.py @@ -260,7 +260,9 @@ class Daemon(DaemonThread): password = config_options.get('password') new_password = config_options.get('new_password') config = SimpleConfig(config_options) + # FIXME this is ugly... config.fee_estimates = self.network.config.fee_estimates.copy() + config.mempool_fees = self.network.config.mempool_fees.copy() cmdname = config.get('cmd') cmd = known_commands[cmdname] if cmd.requires_wallet: diff --git a/lib/simple_config.py b/lib/simple_config.py @@ -4,6 +4,7 @@ import time import os import stat from decimal import Decimal +from typing import Union from copy import deepcopy @@ -278,16 +279,18 @@ class SimpleConfig(PrintError): return get_fee_within_limits @impose_hard_limits_on_fee - def eta_to_fee(self, i): + def eta_to_fee(self, slider_pos) -> Union[int, None]: """Returns fee in sat/kbyte.""" - if i < 4: - j = FEE_ETA_TARGETS[i] - fee = self.fee_estimates.get(j) + slider_pos = max(slider_pos, 0) + slider_pos = min(slider_pos, len(FEE_ETA_TARGETS)) + if slider_pos < len(FEE_ETA_TARGETS): + target_blocks = FEE_ETA_TARGETS[slider_pos] + fee = self.fee_estimates.get(target_blocks) else: - assert i == 4 fee = self.fee_estimates.get(2) if fee is not None: fee += fee/2 + fee = int(fee) return fee def fee_to_depth(self, target_fee): @@ -301,9 +304,9 @@ class SimpleConfig(PrintError): return depth @impose_hard_limits_on_fee - def depth_to_fee(self, i): + def depth_to_fee(self, slider_pos) -> int: """Returns fee in sat/kbyte.""" - target = self.depth_target(i) + target = self.depth_target(slider_pos) depth = 0 for fee, s in self.mempool_fees: depth += s @@ -313,8 +316,10 @@ class SimpleConfig(PrintError): return 0 return fee * 1000 - def depth_target(self, i): - return FEE_DEPTH_TARGETS[i] + def depth_target(self, slider_pos): + slider_pos = max(slider_pos, 0) + slider_pos = min(slider_pos, len(FEE_DEPTH_TARGETS)-1) + return FEE_DEPTH_TARGETS[slider_pos] def eta_target(self, i): if i == len(FEE_ETA_TARGETS): @@ -430,14 +435,35 @@ class SimpleConfig(PrintError): def use_mempool_fees(self): return bool(self.get('mempool_fees', False)) - def fee_per_kb(self, dyn=None, mempool=None): + def _feerate_from_fractional_slider_position(self, fee_level: float, dyn: bool, + mempool: bool) -> Union[int, None]: + fee_level = max(fee_level, 0) + fee_level = min(fee_level, 1) + if dyn: + max_pos = (len(FEE_DEPTH_TARGETS) - 1) if mempool else len(FEE_ETA_TARGETS) + slider_pos = round(fee_level * max_pos) + fee_rate = self.depth_to_fee(slider_pos) if mempool else self.eta_to_fee(slider_pos) + else: + max_pos = len(FEERATE_STATIC_VALUES) - 1 + slider_pos = round(fee_level * max_pos) + fee_rate = FEERATE_STATIC_VALUES[slider_pos] + return fee_rate + + def fee_per_kb(self, dyn: bool=None, mempool: bool=None, fee_level: float=None) -> Union[int, None]: """Returns sat/kvB fee to pay for a txn. Note: might return None. + + fee_level: float between 0.0 and 1.0, representing fee slider position """ if dyn is None: dyn = self.is_dynfee() if mempool is None: mempool = self.use_mempool_fees() + if fee_level is not None: + return self._feerate_from_fractional_slider_position(fee_level, dyn, mempool) + # there is no fee_level specified; will use config. + # note: 'depth_level' and 'fee_level' in config are integer slider positions, + # unlike fee_level here, which (when given) is a float in [0.0, 1.0] if dyn: if mempool: fee_rate = self.depth_to_fee(self.get_depth_level())