commit 53320470f590edcea6d3783b530ece173e0d03ff
parent a161b6e6556dab35e01ab2607f8a9332d7db2c75
Author: Ben Woosley <Ben.Woosley@gmail.com>
Date: Tue, 24 Apr 2018 12:54:14 -0400
Format the transaction window fee rate with 1 decimal place (#4286)
* Fix format_satoshi to properly handle non-integer values
Handling the integer and fraction parts together via string formatting
simplifies the initial composition because the default behavior manages
the - sign, and the incorporation of the fractional part.
* Limit fee rate output to one decimal place
Via a new precision arg
* Introduce format_fee_satoshis and use it for all fee display
Diffstat:
6 files changed, 62 insertions(+), 24 deletions(-)
diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
@@ -671,7 +671,7 @@ class ElectrumWindow(App):
return format_satoshis_plain(amount, self.decimal_point())
def format_amount(self, x, is_diff=False, whitespaces=False):
- return format_satoshis(x, is_diff, 0, self.decimal_point(), whitespaces)
+ return format_satoshis(x, 0, self.decimal_point(), is_diff=is_diff, whitespaces=whitespaces)
def format_amount_and_units(self, x):
return format_satoshis_plain(x, self.decimal_point()) + ' ' + self.base_unit
diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
@@ -44,8 +44,8 @@ from electrum.bitcoin import COIN, is_address, TYPE_ADDRESS
from electrum import constants
from electrum.plugins import run_hook
from electrum.i18n import _
-from electrum.util import (format_time, format_satoshis, PrintError,
- format_satoshis_plain, NotEnoughFunds,
+from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
+ format_satoshis_plain, NotEnoughFunds, PrintError,
UserCancelled, NoDynamicFeeEstimates, profiler,
export_meta, import_meta, bh2u, bfh, InvalidPassword)
from electrum import Transaction
@@ -639,7 +639,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.require_fee_update = False
def format_amount(self, x, is_diff=False, whitespaces=False):
- return format_satoshis(x, is_diff, self.num_zeros, self.decimal_point, whitespaces)
+ return format_satoshis(x, self.num_zeros, self.decimal_point, is_diff=is_diff, whitespaces=whitespaces)
def format_amount_and_units(self, amount):
text = self.format_amount(amount) + ' '+ self.base_unit()
@@ -649,7 +649,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
return text
def format_fee_rate(self, fee_rate):
- return format_satoshis(fee_rate/1000, False, self.num_zeros, 0, False) + ' sat/byte'
+ return format_fee_satoshis(fee_rate/1000, self.num_zeros) + ' sat/byte'
def get_decimal_point(self):
return self.decimal_point
@@ -3192,5 +3192,3 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
self.need_update.set()
self.msg_box(QPixmap(":icons/offline_tx.png"), None, _('Success'), _("Transaction added to wallet history"))
return True
-
-
diff --git a/lib/simple_config.py b/lib/simple_config.py
@@ -7,7 +7,7 @@ import stat
from copy import deepcopy
from .util import (user_dir, print_error, PrintError,
- NoDynamicFeeEstimates, format_satoshis)
+ NoDynamicFeeEstimates, format_fee_satoshis)
from .i18n import _
FEE_ETA_TARGETS = [25, 10, 5, 2]
@@ -367,7 +367,11 @@ class SimpleConfig(PrintError):
text is what we target: static fee / num blocks to confirm in / mempool depth
tooltip is the corresponding estimate (e.g. num blocks for a static fee)
"""
- rate_str = (format_satoshis(fee_rate/1000, False, 0, 0, False) + ' sat/byte') if fee_rate is not None else 'unknown'
+ if fee_rate is None:
+ rate_str = 'unknown'
+ else:
+ rate_str = format_fee_satoshis(fee_rate/1000) + ' sat/byte'
+
if dyn:
if mempool:
depth = self.depth_target(pos)
diff --git a/lib/tests/test_util.py b/lib/tests/test_util.py
@@ -8,6 +8,43 @@ class TestUtil(unittest.TestCase):
expected = "0.00001234"
self.assertEqual(expected, result)
+ def test_format_satoshis_negative(self):
+ result = format_satoshis(-1234)
+ expected = "-0.00001234"
+ self.assertEqual(expected, result)
+
+ def test_format_fee(self):
+ result = format_satoshis(1700/1000, 0, 0)
+ expected = "1.7"
+ self.assertEqual(expected, result)
+
+ def test_format_fee_precision(self):
+ result = format_satoshis(1666/1000, 0, 0, precision=6)
+ expected = "1.666"
+ self.assertEqual(expected, result)
+
+ result = format_satoshis(1666/1000, 0, 0, precision=1)
+ expected = "1.7"
+ self.assertEqual(expected, result)
+
+ def test_format_satoshis_whitespaces(self):
+ result = format_satoshis(12340, whitespaces=True)
+ expected = " 0.0001234 "
+ self.assertEqual(expected, result)
+
+ result = format_satoshis(1234, whitespaces=True)
+ expected = " 0.00001234"
+ self.assertEqual(expected, result)
+
+ def test_format_satoshis_whitespaces_negative(self):
+ result = format_satoshis(-12340, whitespaces=True)
+ expected = " -0.0001234 "
+ self.assertEqual(expected, result)
+
+ result = format_satoshis(-1234, whitespaces=True)
+ expected = " -0.00001234"
+ self.assertEqual(expected, result)
+
def test_format_satoshis_diff_positive(self):
result = format_satoshis(1234, is_diff=True)
expected = "+0.00001234"
@@ -67,4 +104,3 @@ class TestUtil(unittest.TestCase):
def test_parse_URI_parameter_polution(self):
self.assertRaises(Exception, parse_URI, 'bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.0003&label=test&amount=30.0')
-
diff --git a/lib/util.py b/lib/util.py
@@ -412,20 +412,18 @@ def format_satoshis_plain(x, decimal_point = 8):
return "{:.8f}".format(Decimal(x) / scale_factor).rstrip('0').rstrip('.')
-def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespaces=False):
+def format_satoshis(x, num_zeros=0, decimal_point=8, precision=None, is_diff=False, whitespaces=False):
from locale import localeconv
if x is None:
return 'unknown'
- x = int(x) # Some callers pass Decimal
- scale_factor = pow (10, decimal_point)
- integer_part = "{:d}".format(int(abs(x) / scale_factor))
- if x < 0:
- integer_part = '-' + integer_part
- elif is_diff:
- integer_part = '+' + integer_part
+ if precision is None:
+ precision = decimal_point
+ decimal_format = ".0" + str(precision) if precision > 0 else ""
+ if is_diff:
+ decimal_format = '+' + decimal_format
+ result = ("{:" + decimal_format + "f}").format(x / pow (10, decimal_point)).rstrip('0')
+ integer_part, fract_part = result.split(".")
dp = localeconv()['decimal_point']
- fract_part = ("{:0" + str(decimal_point) + "}").format(abs(x) % scale_factor)
- fract_part = fract_part.rstrip('0')
if len(fract_part) < num_zeros:
fract_part += "0" * (num_zeros - len(fract_part))
result = integer_part + dp + fract_part
@@ -434,6 +432,9 @@ def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespa
result = " " * (15 - len(result)) + result
return result
+def format_fee_satoshis(fee, num_zeros=0):
+ return format_satoshis(fee, num_zeros, 0, precision=1)
+
def timestamp_to_datetime(timestamp):
if timestamp is None:
return None
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -45,8 +45,8 @@ import sys
from .i18n import _
from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
- format_satoshis, NoDynamicFeeEstimates, TimeoutException,
- WalletFileException, BitcoinException)
+ format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
+ TimeoutException, WalletFileException, BitcoinException)
from .bitcoin import *
from .version import *
@@ -1169,7 +1169,7 @@ class Abstract_Wallet(PrintError):
if fee is not None:
size = tx.estimated_size()
fee_per_byte = fee / size
- extra.append('%.1f sat/b'%(fee_per_byte))
+ extra.append(format_fee_satoshis(fee_per_byte) + ' sat/b')
if fee is not None and height in (TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED) \
and self.network and self.network.config.has_fee_mempool():
exp_n = self.network.config.fee_to_depth(fee_per_byte)
@@ -2362,4 +2362,3 @@ class Wallet(object):
if wallet_type in wallet_constructors:
return wallet_constructors[wallet_type]
raise RuntimeError("Unknown wallet type: " + str(wallet_type))
-