tx dialog: show various warnings if input amounts cannot be verified (#6217)
see #5749
This commit is contained in:
@@ -132,9 +132,10 @@ class TxDialog(Factory.Popup):
|
||||
self.tx = tx # type: Transaction
|
||||
self._action_button_fn = lambda btn: None
|
||||
|
||||
# if the wallet can populate the inputs with more info, do it now.
|
||||
# as a result, e.g. we might learn an imported address tx is segwit,
|
||||
# or that a beyond-gap-limit address is is_mine
|
||||
# If the wallet can populate the inputs with more info, do it now.
|
||||
# As a result, e.g. we might learn an imported address tx is segwit,
|
||||
# or that a beyond-gap-limit address is is_mine.
|
||||
# note: this might fetch prev txs over the network.
|
||||
tx.add_info_from_wallet(self.wallet)
|
||||
|
||||
def on_open(self):
|
||||
@@ -173,7 +174,7 @@ class TxDialog(Factory.Popup):
|
||||
risk_of_burning_coins = (isinstance(self.tx, PartialTransaction)
|
||||
and self.can_sign
|
||||
and fee is not None
|
||||
and self.tx.is_there_risk_of_burning_coins_as_fees())
|
||||
and bool(self.wallet.get_warning_for_risk_of_burning_coins_as_fees(self.tx)))
|
||||
if fee is not None and not risk_of_burning_coins:
|
||||
self.fee_str = format_amount(fee)
|
||||
fee_per_kb = fee / self.tx.estimated_size() * 1000
|
||||
|
||||
@@ -211,9 +211,10 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
|
||||
self.tx.deserialize()
|
||||
except BaseException as e:
|
||||
raise SerializationError(e)
|
||||
# if the wallet can populate the inputs with more info, do it now.
|
||||
# as a result, e.g. we might learn an imported address tx is segwit,
|
||||
# or that a beyond-gap-limit address is is_mine
|
||||
# If the wallet can populate the inputs with more info, do it now.
|
||||
# As a result, e.g. we might learn an imported address tx is segwit,
|
||||
# or that a beyond-gap-limit address is is_mine.
|
||||
# note: this might fetch prev txs over the network.
|
||||
tx.add_info_from_wallet(self.wallet)
|
||||
|
||||
def do_broadcast(self):
|
||||
@@ -479,8 +480,9 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
|
||||
fee_str += ' - ' + _('Warning') + ': ' + _("high fee") + '!'
|
||||
if isinstance(self.tx, PartialTransaction):
|
||||
risk_of_burning_coins = (can_sign and fee is not None
|
||||
and self.tx.is_there_risk_of_burning_coins_as_fees())
|
||||
self.fee_warning_icon.setVisible(risk_of_burning_coins)
|
||||
and self.wallet.get_warning_for_risk_of_burning_coins_as_fees(self.tx))
|
||||
self.fee_warning_icon.setToolTip(str(risk_of_burning_coins))
|
||||
self.fee_warning_icon.setVisible(bool(risk_of_burning_coins))
|
||||
self.fee_label.setText(fee_str)
|
||||
self.size_label.setText(size_str)
|
||||
if ln_amount is None:
|
||||
@@ -596,10 +598,6 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
|
||||
pixmap_size = round(2 * char_width_in_lineedit())
|
||||
pixmap = pixmap.scaled(pixmap_size, pixmap_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
self.fee_warning_icon.setPixmap(pixmap)
|
||||
self.fee_warning_icon.setToolTip(_("Warning") + ": "
|
||||
+ _("The fee could not be verified. Signing non-segwit inputs is risky:\n"
|
||||
"if this transaction was maliciously modified before you sign,\n"
|
||||
"you might end up paying a higher mining fee than displayed."))
|
||||
self.fee_warning_icon.setVisible(False)
|
||||
fee_hbox.addWidget(self.fee_warning_icon)
|
||||
fee_hbox.addStretch(1)
|
||||
|
||||
@@ -1953,25 +1953,6 @@ class PartialTransaction(Transaction):
|
||||
for txin in self.inputs():
|
||||
txin.convert_utxo_to_witness_utxo()
|
||||
|
||||
def is_there_risk_of_burning_coins_as_fees(self) -> bool:
|
||||
"""Returns whether there is risk of burning coins as fees if we sign.
|
||||
|
||||
Note:
|
||||
- legacy sighash does not commit to any input amounts
|
||||
- BIP-0143 sighash only commits to the *corresponding* input amount
|
||||
- BIP-taproot sighash commits to *all* input amounts
|
||||
"""
|
||||
for txin in self.inputs():
|
||||
# if we have full previous tx, we *know* the input amount
|
||||
if txin.utxo:
|
||||
continue
|
||||
# if we have just the previous output, we only have guarantees if
|
||||
# the sighash commits to this data
|
||||
if txin.witness_utxo and Transaction.is_segwit_input(txin):
|
||||
continue
|
||||
return True
|
||||
return False
|
||||
|
||||
def remove_signatures(self):
|
||||
for txin in self.inputs():
|
||||
txin.part_sigs = {}
|
||||
|
||||
@@ -2023,6 +2023,40 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
||||
self.sign_transaction(tx, password)
|
||||
return tx
|
||||
|
||||
def get_warning_for_risk_of_burning_coins_as_fees(self, tx: 'PartialTransaction') -> Optional[str]:
|
||||
"""Returns a warning message if there is risk of burning coins as fees if we sign.
|
||||
Note that if not all inputs are ismine, e.g. coinjoin, the risk is not just about fees.
|
||||
|
||||
Note:
|
||||
- legacy sighash does not commit to any input amounts
|
||||
- BIP-0143 sighash only commits to the *corresponding* input amount
|
||||
- BIP-taproot sighash commits to *all* input amounts
|
||||
"""
|
||||
assert isinstance(tx, PartialTransaction)
|
||||
# if we have all full previous txs, we *know* all the input amounts -> fine
|
||||
if all([txin.utxo for txin in tx.inputs()]):
|
||||
return None
|
||||
# a single segwit input -> fine
|
||||
if len(tx.inputs()) == 1 and Transaction.is_segwit_input(tx.inputs()[0]) and tx.inputs()[0].witness_utxo:
|
||||
return None
|
||||
# coinjoin or similar
|
||||
if any([not self.is_mine(txin.address) for txin in tx.inputs()]):
|
||||
return (_("Warning") + ": "
|
||||
+ _("The input amounts could not be verified as the previous transactions are missing.\n"
|
||||
"The amount of money being spent CANNOT be verified."))
|
||||
# some inputs are legacy
|
||||
if any([not Transaction.is_segwit_input(txin) for txin in tx.inputs()]):
|
||||
return (_("Warning") + ": "
|
||||
+ _("The fee could not be verified. Signing non-segwit inputs is risky:\n"
|
||||
"if this transaction was maliciously modified before you sign,\n"
|
||||
"you might end up paying a higher mining fee than displayed."))
|
||||
# all inputs are segwit
|
||||
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014843.html
|
||||
return (_("Warning") + ": "
|
||||
+ _("If you received this transaction from an untrusted device, "
|
||||
"do not accept to sign it more than once,\n"
|
||||
"otherwise you could end up paying a different fee."))
|
||||
|
||||
|
||||
class Simple_Wallet(Abstract_Wallet):
|
||||
# wallet with a single keystore
|
||||
|
||||
Reference in New Issue
Block a user