1
0

tx dialog: show various warnings if input amounts cannot be verified (#6217)

see #5749
This commit is contained in:
ghost43
2020-06-08 14:24:41 +00:00
committed by GitHub
parent 61ccc1ccd3
commit 947af92126
4 changed files with 46 additions and 32 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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 = {}

View File

@@ -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