From 2ab8234e9c08b5d35f6bf8d07ba587975cf86e53 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Fri, 9 Nov 2018 20:04:06 +0100 Subject: [PATCH] RBF batching: smarter fee handling --- electrum/gui/qt/main_window.py | 3 ++- electrum/wallet.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index d900fe651..fa71b5a9c 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -1203,7 +1203,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): _('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.') + ' ' + _("You can disable this setting in '{}'.").format(_('Preferences')) + '\n' + - _('Also, dust is not kept as change, but added to the fee.')) + _('Also, dust is not kept as change, but added to the fee.') + '\n' + + _('Also, when batching RBF transactions, BIP 125 imposes a lower bound on the fee.')) QMessageBox.information(self, 'Fee rounding', text) self.feerounding_icon = QPushButton(QIcon(':icons/info.png'), '') diff --git a/electrum/wallet.py b/electrum/wallet.py index 7d0dda2d9..ca9af202c 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -550,6 +550,9 @@ class Abstract_Wallet(AddressSynchronizer): for output_idx, o in enumerate(tx.outputs()): if self.is_mine(o.address) and self.spent_outpoints[tx.txid()].get(output_idx): continue + # all inputs should be is_mine + if not all([self.is_mine(self.get_txin_address(txin)) for txin in tx.inputs()]): + continue # prefer txns already in mempool (vs local) if tx_mined_status.height == TX_HEIGHT_LOCAL: candidate = tx @@ -613,10 +616,18 @@ class Abstract_Wallet(AddressSynchronizer): # If there is an unconfirmed RBF tx, merge with it base_tx = self.get_unconfirmed_base_tx_for_batching() if config.get('batch_rbf', False) and base_tx: + is_local = self.get_tx_height(base_tx.txid()).height == TX_HEIGHT_LOCAL base_tx = Transaction(base_tx.serialize()) base_tx.deserialize(force_full_parse=True) base_tx.remove_signatures() base_tx.add_inputs_info(self) + base_tx_fee = base_tx.get_fee() + relayfeerate = self.relayfee() / 1000 + original_fee_estimator = fee_estimator + def fee_estimator(size: int) -> int: + lower_bound = base_tx_fee + round(size * relayfeerate) + lower_bound = lower_bound if not is_local else 0 + return max(lower_bound, original_fee_estimator(size)) txi = base_tx.inputs() txo = list(filter(lambda o: not self.is_change(o.address), base_tx.outputs())) else: