Set the RBF flat to all transactions, and remove the 'use_rbf'
preference from the GUI, because the mempoolfullrbf option in Bitcoin 0.24 makes RBF signaling pretty meaningless. Fixes #8088. Note: RBF remains disabled for channel funding transactions. In that case, the flag is actually only used as a semaphore between different instances of the same wallet.
This commit is contained in:
@@ -675,7 +675,7 @@ class Commands:
|
||||
|
||||
@command('wp')
|
||||
async def payto(self, destination, amount, fee=None, feerate=None, from_addr=None, from_coins=None, change_addr=None,
|
||||
nocheck=False, unsigned=False, rbf=None, password=None, locktime=None, addtransaction=False, wallet: Abstract_Wallet = None):
|
||||
nocheck=False, unsigned=False, rbf=True, password=None, locktime=None, addtransaction=False, wallet: Abstract_Wallet = None):
|
||||
"""Create a transaction. """
|
||||
self.nocheck = nocheck
|
||||
tx_fee = satoshis(fee)
|
||||
|
||||
@@ -26,7 +26,6 @@ Builder.load_string('''
|
||||
message: ''
|
||||
warning: ''
|
||||
extra_fee: ''
|
||||
show_final: False
|
||||
size_hint: 0.8, 0.8
|
||||
pos_hint: {'top':0.9}
|
||||
method: 0
|
||||
@@ -82,17 +81,6 @@ Builder.load_string('''
|
||||
range: 0, 4
|
||||
step: 1
|
||||
on_value: root.on_slider(self.value)
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
size_hint: 1, 0.2
|
||||
Label:
|
||||
text: _('Final')
|
||||
opacity: int(root.show_final)
|
||||
CheckBox:
|
||||
id: final_cb
|
||||
opacity: int(root.show_final)
|
||||
disabled: not root.show_final
|
||||
on_release: root.update_tx()
|
||||
Label:
|
||||
text: root.warning
|
||||
text_size: self.width, None
|
||||
@@ -122,7 +110,7 @@ Builder.load_string('''
|
||||
|
||||
class ConfirmTxDialog(FeeSliderDialog, Factory.Popup):
|
||||
|
||||
def __init__(self, app: 'ElectrumWindow', amount, make_tx, on_pay, *, show_final=True):
|
||||
def __init__(self, app: 'ElectrumWindow', amount, make_tx, on_pay):
|
||||
|
||||
Factory.Popup.__init__(self)
|
||||
FeeSliderDialog.__init__(self, app.electrum_config, self.ids.slider)
|
||||
@@ -130,16 +118,14 @@ class ConfirmTxDialog(FeeSliderDialog, Factory.Popup):
|
||||
self.amount = amount
|
||||
self.make_tx = make_tx
|
||||
self.on_pay = on_pay
|
||||
self.show_final = show_final
|
||||
self.update_slider()
|
||||
self.update_text()
|
||||
self.update_tx()
|
||||
|
||||
def update_tx(self):
|
||||
rbf = not bool(self.ids.final_cb.active) if self.show_final else False
|
||||
try:
|
||||
# make unsigned transaction
|
||||
tx = self.make_tx(rbf)
|
||||
tx = self.make_tx()
|
||||
except NotEnoughFunds:
|
||||
self.warning = _("Not enough funds")
|
||||
self.ids.ok_button.disabled = True
|
||||
|
||||
@@ -438,7 +438,7 @@ class SendScreen(CScreen, Logger):
|
||||
outputs = invoice.outputs
|
||||
amount = sum(map(lambda x: x.value, outputs)) if not any(parse_max_spend(x.value) for x in outputs) else '!'
|
||||
coins = self.app.wallet.get_spendable_coins(None)
|
||||
make_tx = lambda rbf: self.app.wallet.make_unsigned_transaction(coins=coins, outputs=outputs, rbf=rbf)
|
||||
make_tx = lambda: self.app.wallet.make_unsigned_transaction(coins=coins, outputs=outputs)
|
||||
on_pay = lambda tx: self.app.protected(_('Send payment?'), self.send_tx, (tx, invoice))
|
||||
d = ConfirmTxDialog(self.app, amount=amount, make_tx=make_tx, on_pay=on_pay)
|
||||
d.open()
|
||||
|
||||
@@ -130,16 +130,6 @@ Pane {
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: useRbf
|
||||
text: qsTr('Use Replace-By-Fee')
|
||||
Layout.columnSpan: 2
|
||||
onCheckedChanged: {
|
||||
if (activeFocus)
|
||||
Config.useRbf = checked
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr('Default request expiry')
|
||||
Layout.fillWidth: false
|
||||
@@ -269,7 +259,6 @@ Pane {
|
||||
lnRoutingType.currentIndex = Config.useGossip ? 0 : 1
|
||||
useFallbackAddress.checked = Config.useFallbackAddress
|
||||
enableDebugLogs.checked = Config.enableDebugLogs
|
||||
useRbf.checked = Config.useRbf
|
||||
useRecoverableChannels.checked = Config.useRecoverableChannels
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,16 +146,6 @@ class QEConfig(AuthMixin, QObject):
|
||||
self.config.set_key('gui_enable_debug_logs', enable)
|
||||
self.enableDebugLogsChanged.emit()
|
||||
|
||||
useRbfChanged = pyqtSignal()
|
||||
@pyqtProperty(bool, notify=useRbfChanged)
|
||||
def useRbf(self):
|
||||
return self.config.get('use_rbf', True)
|
||||
|
||||
@useRbf.setter
|
||||
def useRbf(self, useRbf):
|
||||
self.config.set_key('use_rbf', useRbf)
|
||||
self.useRbfChanged.emit()
|
||||
|
||||
useRecoverableChannelsChanged = pyqtSignal()
|
||||
@pyqtProperty(bool, notify=useRecoverableChannelsChanged)
|
||||
def useRecoverableChannels(self):
|
||||
|
||||
@@ -455,9 +455,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
# see qt/confirm_tx_dialog qt/main_window
|
||||
tx = self.wallet.make_unsigned_transaction(coins=coins,outputs=outputs, fee=None)
|
||||
self._logger.info(str(tx.to_json()))
|
||||
|
||||
use_rbf = bool(self.wallet.config.get('use_rbf', True))
|
||||
tx.set_rbf(use_rbf)
|
||||
tx.set_rbf(True)
|
||||
self.sign(tx, broadcast=True)
|
||||
|
||||
@auth_protect
|
||||
|
||||
@@ -113,8 +113,7 @@ class TxEditor:
|
||||
self.tx = None
|
||||
self.main_window.show_error(str(e))
|
||||
raise
|
||||
use_rbf = bool(self.config.get('use_rbf', True))
|
||||
self.tx.set_rbf(use_rbf)
|
||||
self.tx.set_rbf(True)
|
||||
|
||||
def have_enough_funds_assuming_zero_fees(self) -> bool:
|
||||
try:
|
||||
|
||||
@@ -47,6 +47,8 @@ class _BaseRBFDialog(WindowModalDialog):
|
||||
|
||||
ok_button = OkButton(self)
|
||||
self.adv_button = QPushButton(_("Show advanced settings"))
|
||||
self.adv_button.setEnabled(False)
|
||||
self.adv_button.setVisible(False)
|
||||
warning_label = WWLabel('\n')
|
||||
warning_label.setStyleSheet(ColorScheme.RED.as_stylesheet())
|
||||
self.feerate_e = FeerateEdit(lambda: 0)
|
||||
@@ -115,21 +117,18 @@ class _BaseRBFDialog(WindowModalDialog):
|
||||
vbox.addWidget(adv_widget)
|
||||
|
||||
def _add_advanced_options(self, adv_vbox: QVBoxLayout) -> None:
|
||||
self.cb_rbf = QCheckBox(_('Keep Replace-By-Fee enabled'))
|
||||
self.cb_rbf.setChecked(True)
|
||||
adv_vbox.addWidget(self.cb_rbf)
|
||||
pass
|
||||
|
||||
def run(self) -> None:
|
||||
if not self.exec_():
|
||||
return
|
||||
is_rbf = self.cb_rbf.isChecked()
|
||||
new_fee_rate = self.feerate_e.get_amount()
|
||||
try:
|
||||
new_tx = self.rbf_func(new_fee_rate)
|
||||
except Exception as e:
|
||||
self.window.show_error(str(e))
|
||||
return
|
||||
new_tx.set_rbf(is_rbf)
|
||||
new_tx.set_rbf(True)
|
||||
tx_label = self.wallet.get_label_for_txid(self.txid)
|
||||
self.window.show_transaction(new_tx, tx_desc=tx_label)
|
||||
# TODO maybe save tx_label as label for new tx??
|
||||
@@ -164,10 +163,8 @@ class BumpFeeDialog(_BaseRBFDialog):
|
||||
)
|
||||
|
||||
def _add_advanced_options(self, adv_vbox: QVBoxLayout) -> None:
|
||||
self.cb_rbf = QCheckBox(_('Keep Replace-By-Fee enabled'))
|
||||
self.cb_rbf.setChecked(True)
|
||||
adv_vbox.addWidget(self.cb_rbf)
|
||||
|
||||
self.adv_button.setVisible(True)
|
||||
self.adv_button.setEnabled(True)
|
||||
self.strat_combo = QComboBox()
|
||||
options = [
|
||||
_("decrease change, or add new inputs, or decrease any outputs"),
|
||||
|
||||
@@ -118,21 +118,8 @@ class SettingsDialog(QDialog, QtEventListener):
|
||||
self.config.set_key('bip21_lightning', bool(x))
|
||||
bip21_lightning_cb.stateChanged.connect(on_bip21_lightning)
|
||||
|
||||
use_rbf = bool(self.config.get('use_rbf', True))
|
||||
use_rbf_cb = QCheckBox(_('Use Replace-By-Fee'))
|
||||
use_rbf_cb.setChecked(use_rbf)
|
||||
use_rbf_cb.setToolTip(
|
||||
_('If you check this box, your transactions will be marked as non-final,') + '\n' + \
|
||||
_('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
|
||||
_('Note that some merchants do not accept non-final transactions until they are confirmed.'))
|
||||
def on_use_rbf(x):
|
||||
self.config.set_key('use_rbf', bool(x))
|
||||
batch_rbf_cb.setEnabled(bool(x))
|
||||
use_rbf_cb.stateChanged.connect(on_use_rbf)
|
||||
|
||||
batch_rbf_cb = QCheckBox(_('Batch RBF transactions'))
|
||||
batch_rbf_cb = QCheckBox(_('Batch unconfirmed transactions'))
|
||||
batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False)))
|
||||
batch_rbf_cb.setEnabled(use_rbf)
|
||||
batch_rbf_cb.setToolTip(
|
||||
_('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \
|
||||
_('This will save fees.'))
|
||||
@@ -505,7 +492,6 @@ class SettingsDialog(QDialog, QtEventListener):
|
||||
invoices_widgets.append((bip21_lightning_cb, None))
|
||||
tx_widgets = []
|
||||
tx_widgets.append((usechange_cb, None))
|
||||
tx_widgets.append((use_rbf_cb, None))
|
||||
tx_widgets.append((batch_rbf_cb, None))
|
||||
tx_widgets.append((preview_cb, None))
|
||||
tx_widgets.append((unconf_cb, None))
|
||||
|
||||
@@ -680,9 +680,6 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
|
||||
vbox_right.addWidget(self.size_label)
|
||||
self.rbf_label = TxDetailLabel()
|
||||
vbox_right.addWidget(self.rbf_label)
|
||||
self.rbf_cb = QCheckBox(_('Replace by fee'))
|
||||
self.rbf_cb.setChecked(bool(self.config.get('use_rbf', True)))
|
||||
vbox_right.addWidget(self.rbf_cb)
|
||||
|
||||
self.locktime_final_label = TxDetailLabel()
|
||||
vbox_right.addWidget(self.locktime_final_label)
|
||||
@@ -713,7 +710,6 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
|
||||
|
||||
# set visibility after parenting can be determined by Qt
|
||||
self.rbf_label.setVisible(self.finalized)
|
||||
self.rbf_cb.setVisible(not self.finalized)
|
||||
self.locktime_final_label.setVisible(self.finalized)
|
||||
self.locktime_setter_widget.setVisible(not self.finalized)
|
||||
|
||||
@@ -982,11 +978,11 @@ class PreviewTxDialog(BaseTxDialog, TxEditor):
|
||||
assert self.tx
|
||||
self.finalized = True
|
||||
self.stop_editor_updates()
|
||||
self.tx.set_rbf(self.rbf_cb.isChecked())
|
||||
self.tx.set_rbf(True)
|
||||
locktime = self.locktime_e.get_locktime()
|
||||
if locktime is not None:
|
||||
self.tx.locktime = locktime
|
||||
for widget in [self.fee_slider, self.fee_combo, self.feecontrol_fields, self.rbf_cb,
|
||||
for widget in [self.fee_slider, self.fee_combo, self.feecontrol_fields,
|
||||
self.locktime_setter_widget, self.locktime_e]:
|
||||
widget.setEnabled(False)
|
||||
widget.setVisible(False)
|
||||
|
||||
+4
-10
@@ -204,8 +204,7 @@ async def sweep(
|
||||
locktime = get_locktime_for_new_transaction(network)
|
||||
|
||||
tx = PartialTransaction.from_io(inputs, outputs, locktime=locktime, version=tx_version)
|
||||
rbf = bool(config.get('use_rbf', True))
|
||||
tx.set_rbf(rbf)
|
||||
tx.set_rbf(True)
|
||||
tx.sign(keypairs)
|
||||
return tx
|
||||
|
||||
@@ -1420,8 +1419,6 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
if not tx:
|
||||
return 2, 'unknown'
|
||||
is_final = tx and tx.is_final()
|
||||
if not is_final:
|
||||
extra.append('rbf')
|
||||
fee = self.adb.get_tx_fee(tx_hash)
|
||||
if fee is not None:
|
||||
size = tx.estimated_size()
|
||||
@@ -1569,7 +1566,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
fee=None,
|
||||
change_addr: str = None,
|
||||
is_sweep=False,
|
||||
rbf=False) -> PartialTransaction:
|
||||
rbf=True) -> PartialTransaction:
|
||||
"""Can raise NotEnoughFunds or NoDynamicFeeEstimates."""
|
||||
|
||||
if not coins: # any bitcoin tx must have at least 1 input by consensus
|
||||
@@ -1668,7 +1665,6 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
|
||||
# Timelock tx to current height.
|
||||
tx.locktime = get_locktime_for_new_transaction(self.network)
|
||||
|
||||
tx.set_rbf(rbf)
|
||||
tx.add_info_from_wallet(self)
|
||||
run_hook('make_unsigned_transaction', self, tx)
|
||||
@@ -1677,7 +1673,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
def mktx(self, *,
|
||||
outputs: List[PartialTxOutput],
|
||||
password=None, fee=None, change_addr=None,
|
||||
domain=None, rbf=False, nonlocal_only=False,
|
||||
domain=None, rbf=True, nonlocal_only=False,
|
||||
tx_version=None, sign=True) -> PartialTransaction:
|
||||
coins = self.get_spendable_coins(domain, nonlocal_only=nonlocal_only)
|
||||
tx = self.make_unsigned_transaction(
|
||||
@@ -2726,7 +2722,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
pass
|
||||
|
||||
def create_transaction(self, outputs, *, fee=None, feerate=None, change_addr=None, domain_addr=None, domain_coins=None,
|
||||
unsigned=False, rbf=None, password=None, locktime=None):
|
||||
unsigned=False, rbf=True, password=None, locktime=None):
|
||||
if fee is not None and feerate is not None:
|
||||
raise Exception("Cannot specify both 'fee' and 'feerate' at the same time!")
|
||||
coins = self.get_spendable_coins(domain_addr)
|
||||
@@ -2744,8 +2740,6 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
change_addr=change_addr)
|
||||
if locktime is not None:
|
||||
tx.locktime = locktime
|
||||
if rbf is None:
|
||||
rbf = bool(self.config.get('use_rbf', True))
|
||||
tx.set_rbf(rbf)
|
||||
if not unsigned:
|
||||
self.sign_transaction(tx, password)
|
||||
|
||||
Reference in New Issue
Block a user