Merge pull request #3878 from SomberNight/coinchooser_output_rounding
coinchooser: make output value rounding configurable
This commit is contained in:
commit
cccf380753
|
@ -1136,7 +1136,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
|||
def feerounding_onclick():
|
||||
text = (self.feerounding_text + '\n\n' +
|
||||
_('To somewhat protect your privacy, Electrum tries to create change with similar precision to other outputs.') + ' ' +
|
||||
_('At most 100 satoshis might be lost due to this rounding.') + '\n' +
|
||||
_('At most 100 satoshis might be lost due to this rounding.') + ' ' +
|
||||
_("You can disable this setting in '{}'.").format(_('Preferences')) + '\n' +
|
||||
_('Also, dust is not kept as change, but added to the fee.'))
|
||||
QMessageBox.information(self, 'Fee rounding', text)
|
||||
|
||||
|
@ -2893,6 +2894,18 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
|||
unconf_cb.stateChanged.connect(on_unconf)
|
||||
tx_widgets.append((unconf_cb, None))
|
||||
|
||||
def on_outrounding(x):
|
||||
self.config.set_key('coin_chooser_output_rounding', bool(x))
|
||||
enable_outrounding = self.config.get('coin_chooser_output_rounding', False)
|
||||
outrounding_cb = QCheckBox(_('Enable output value rounding'))
|
||||
outrounding_cb.setToolTip(
|
||||
_('Set the value of the change output so that it has similar precision to the other outputs.') + '\n' +
|
||||
_('This might improve your privacy somewhat.') + '\n' +
|
||||
_('If enabled, at most 100 satoshis might be lost due to this, per transaction.'))
|
||||
outrounding_cb.setChecked(enable_outrounding)
|
||||
outrounding_cb.stateChanged.connect(on_outrounding)
|
||||
tx_widgets.append((outrounding_cb, None))
|
||||
|
||||
# Fiat Currency
|
||||
hist_checkbox = QCheckBox()
|
||||
fiat_address_checkbox = QCheckBox()
|
||||
|
|
|
@ -87,6 +87,8 @@ def strip_unneeded(bkts, sufficient_funds):
|
|||
|
||||
class CoinChooserBase(PrintError):
|
||||
|
||||
enable_output_value_rounding = False
|
||||
|
||||
def keys(self, coins):
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -135,7 +137,13 @@ class CoinChooserBase(PrintError):
|
|||
zeroes = [trailing_zeroes(i) for i in output_amounts]
|
||||
min_zeroes = min(zeroes)
|
||||
max_zeroes = max(zeroes)
|
||||
|
||||
if n > 1:
|
||||
zeroes = range(max(0, min_zeroes - 1), (max_zeroes + 1) + 1)
|
||||
else:
|
||||
# if there is only one change output, this will ensure that we aim
|
||||
# to have one that is exactly as precise as the most precise output
|
||||
zeroes = [min_zeroes]
|
||||
|
||||
# Calculate change; randomize it a bit if using more than 1 output
|
||||
remaining = change_amount
|
||||
|
@ -150,8 +158,10 @@ class CoinChooserBase(PrintError):
|
|||
n -= 1
|
||||
|
||||
# Last change output. Round down to maximum precision but lose
|
||||
# no more than 100 satoshis to fees (2dp)
|
||||
N = pow(10, min(2, zeroes[0]))
|
||||
# no more than 10**max_dp_to_round_for_privacy
|
||||
# e.g. a max of 2 decimal places means losing 100 satoshis to fees
|
||||
max_dp_to_round_for_privacy = 2 if self.enable_output_value_rounding else 0
|
||||
N = pow(10, min(max_dp_to_round_for_privacy, zeroes[0]))
|
||||
amount = (remaining // N) * N
|
||||
amounts.append(amount)
|
||||
|
||||
|
@ -370,4 +380,6 @@ def get_name(config):
|
|||
|
||||
def get_coin_chooser(config):
|
||||
klass = COIN_CHOOSERS[get_name(config)]
|
||||
return klass()
|
||||
coinchooser = klass()
|
||||
coinchooser.enable_output_value_rounding = config.get('coin_chooser_output_rounding', False)
|
||||
return coinchooser
|
||||
|
|
Loading…
Reference in New Issue