add CPFP (child pays for parent) dialog to the Qt GUI
This commit is contained in:
parent
9e1931587d
commit
15b404b9de
|
@ -142,7 +142,7 @@ class HistoryList(MyTreeWidget):
|
||||||
height, conf, timestamp = self.wallet.get_tx_height(tx_hash)
|
height, conf, timestamp = self.wallet.get_tx_height(tx_hash)
|
||||||
tx = self.wallet.transactions.get(tx_hash)
|
tx = self.wallet.transactions.get(tx_hash)
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
||||||
rbf = is_mine and height <=0 and tx and not tx.is_final()
|
is_unconfirmed = height <= 0
|
||||||
menu = QMenu()
|
menu = QMenu()
|
||||||
|
|
||||||
menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data))
|
menu.addAction(_("Copy %s")%column_title, lambda: self.parent.app.clipboard().setText(column_data))
|
||||||
|
@ -150,8 +150,14 @@ class HistoryList(MyTreeWidget):
|
||||||
menu.addAction(_("Edit %s")%column_title, lambda: self.editItem(item, column))
|
menu.addAction(_("Edit %s")%column_title, lambda: self.editItem(item, column))
|
||||||
|
|
||||||
menu.addAction(_("Details"), lambda: self.parent.show_transaction(tx))
|
menu.addAction(_("Details"), lambda: self.parent.show_transaction(tx))
|
||||||
if rbf:
|
if is_unconfirmed and tx:
|
||||||
menu.addAction(_("Increase fee"), lambda: self.parent.bump_fee_dialog(tx))
|
rbf = is_mine and not tx.is_final()
|
||||||
|
if rbf:
|
||||||
|
menu.addAction(_("Increase fee"), lambda: self.parent.bump_fee_dialog(tx))
|
||||||
|
else:
|
||||||
|
child_tx = self.wallet.cpfp(tx, 0)
|
||||||
|
if child_tx:
|
||||||
|
menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp(tx, child_tx))
|
||||||
if tx_URL:
|
if tx_URL:
|
||||||
menu.addAction(_("View on block explorer"), lambda: webbrowser.open(tx_URL))
|
menu.addAction(_("View on block explorer"), lambda: webbrowser.open(tx_URL))
|
||||||
menu.exec_(self.viewport().mapToGlobal(position))
|
menu.exec_(self.viewport().mapToGlobal(position))
|
||||||
|
|
|
@ -2767,6 +2767,33 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
vbox.addLayout(Buttons(CloseButton(d)))
|
vbox.addLayout(Buttons(CloseButton(d)))
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
|
def cpfp(self, parent_tx, new_tx):
|
||||||
|
total_size = parent_tx.estimated_size() + new_tx.estimated_size()
|
||||||
|
d = WindowModalDialog(self, _('Child Pays for Parent'))
|
||||||
|
vbox = QVBoxLayout(d)
|
||||||
|
vbox.addWidget(QLabel(_('Total size') + ': %d bytes'% total_size))
|
||||||
|
max_fee = new_tx.output_value()
|
||||||
|
vbox.addWidget(QLabel(_('Max fee') + ': %s'% self.format_amount(max_fee) + ' ' + self.base_unit()))
|
||||||
|
vbox.addWidget(QLabel(_('Child fee' + ':')))
|
||||||
|
fee_e = BTCAmountEdit(self.get_decimal_point)
|
||||||
|
fee = self.config.fee_per_kb() * total_size / 1000
|
||||||
|
fee_e.setAmount(fee)
|
||||||
|
vbox.addWidget(fee_e)
|
||||||
|
def on_rate(dyn, pos, fee_rate):
|
||||||
|
fee = fee_rate * total_size / 1000
|
||||||
|
fee_e.setAmount(min(max_fee, fee))
|
||||||
|
fee_slider = FeeSlider(self, self.config, on_rate)
|
||||||
|
vbox.addWidget(fee_slider)
|
||||||
|
vbox.addLayout(Buttons(CancelButton(d), OkButton(d)))
|
||||||
|
if not d.exec_():
|
||||||
|
return
|
||||||
|
fee = fee_e.get_amount()
|
||||||
|
if fee > max_fee:
|
||||||
|
self.show_error(_('Max fee exceeded'))
|
||||||
|
return
|
||||||
|
new_tx = self.wallet.cpfp(parent_tx, fee)
|
||||||
|
new_tx.set_sequence(0)
|
||||||
|
self.show_transaction(new_tx)
|
||||||
|
|
||||||
def bump_fee_dialog(self, tx):
|
def bump_fee_dialog(self, tx):
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
||||||
|
|
|
@ -1042,6 +1042,25 @@ class Abstract_Wallet(PrintError):
|
||||||
raise BaseException(_('Cannot bump fee: cound not find suitable outputs'))
|
raise BaseException(_('Cannot bump fee: cound not find suitable outputs'))
|
||||||
return Transaction.from_io(inputs, outputs)
|
return Transaction.from_io(inputs, outputs)
|
||||||
|
|
||||||
|
def cpfp(self, tx, fee):
|
||||||
|
txid = tx.txid()
|
||||||
|
for i, o in enumerate(tx.outputs()):
|
||||||
|
otype, address, value = o
|
||||||
|
if otype == TYPE_ADDRESS and self.is_mine(address):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
coins = self.get_addr_utxo(address)
|
||||||
|
for item in coins:
|
||||||
|
if item['prevout_hash'] == txid and item['prevout_n'] == i:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
self.add_input_info(item)
|
||||||
|
inputs = [item]
|
||||||
|
outputs = [(TYPE_ADDRESS, address, value - fee)]
|
||||||
|
return Transaction.from_io(inputs, outputs)
|
||||||
|
|
||||||
def add_input_info(self, txin):
|
def add_input_info(self, txin):
|
||||||
# Add address for utxo that are in wallet
|
# Add address for utxo that are in wallet
|
||||||
if txin.get('scriptSig') == '':
|
if txin.get('scriptSig') == '':
|
||||||
|
|
Loading…
Reference in New Issue