electrum

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

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:
Mgui/kivy/main_window.py | 2+-
Mgui/qt/main_window.py | 10++++------
Mlib/simple_config.py | 8++++++--
Mlib/tests/test_util.py | 38+++++++++++++++++++++++++++++++++++++-
Mlib/util.py | 21+++++++++++----------
Mlib/wallet.py | 7+++----
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)) -