Browse Source

transaction: for witness v0 txins, put both UTXO and WIT_UTXO in psbt

Until now we have been only putting PSBT_IN_NON_WITNESS_UTXO (="UTXO", full tx)
in segwit witness v0 txins, as signers wanted the full tx anyway due to
bip-143 sighash issue [0], and as WITNESS_UTXO can be calculated from UTXO.

My reading of bip-174 is that either behaviour is correct, but
achow101 said bip-174 expects PSBT_IN_WITNESS_UTXO for segwit inputs.
Regardless, including both fields does not increase the tx size too much
(UTXO can be very large ofc but we were already including that, WIT_UTXO is small).
This also might increase compatibility with some other software - I've found
some issues where this might have been the culprit [1][2][3].

closes https://github.com/spesmilo/electrum/issues/8039

related:
[0] https://github.com/spesmilo/electrum/pull/6198
[1] https://github.com/cryptoadvance/specter-desktop/issues/868
[2] https://github.com/cryptoadvance/specter-desktop/issues/1046
[3] https://github.com/cryptoadvance/specter-desktop/issues/1544
patch-4
SomberNight 2 years ago
parent
commit
d3227d7489
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 2
      electrum/tests/__init__.py
  2. 98
      electrum/tests/test_wallet_vertical.py
  3. 11
      electrum/transaction.py
  4. 10
      electrum/wallet.py

2
electrum/tests/__init__.py

@ -36,6 +36,8 @@ class SequentialTestCase(unittest.TestCase):
class ElectrumTestCase(SequentialTestCase):
"""Base class for our unit tests."""
# maxDiff = None
def setUp(self):
super().setUp()
self.asyncio_loop, self._stop_loop, self._loop_thread = util.create_and_start_event_loop()

98
electrum/tests/test_wallet_vertical.py

File diff suppressed because one or more lines are too long

11
electrum/transaction.py

@ -1250,7 +1250,6 @@ class PartialTxInput(TxInput, PSBTSection):
return
self._utxo = tx
self.validate_data()
self.ensure_there_is_only_one_utxo()
@property
def witness_utxo(self):
@ -1260,7 +1259,6 @@ class PartialTxInput(TxInput, PSBTSection):
def witness_utxo(self, value: Optional[TxOutput]):
self._witness_utxo = value
self.validate_data()
self.ensure_there_is_only_one_utxo()
def to_json(self):
d = super().to_json()
@ -1387,7 +1385,6 @@ class PartialTxInput(TxInput, PSBTSection):
self._unknown[full_key] = val
def serialize_psbt_section_kvs(self, wr):
self.ensure_there_is_only_one_utxo()
if self.witness_utxo:
wr(PSBTInputType.WITNESS_UTXO, self.witness_utxo.serialize_to_network())
if self.utxo:
@ -1515,16 +1512,10 @@ class PartialTxInput(TxInput, PSBTSection):
if other_txin.witness_script is not None:
self.witness_script = other_txin.witness_script
self._unknown.update(other_txin._unknown)
self.ensure_there_is_only_one_utxo()
self.validate_data()
# try to finalize now
self.finalize()
def ensure_there_is_only_one_utxo(self):
# we prefer having the full previous tx, even for segwit inputs. see #6198
# for witness v1, witness_utxo will be enough though
if self.utxo is not None and self.witness_utxo is not None:
self.witness_utxo = None
def convert_utxo_to_witness_utxo(self) -> None:
if self.utxo:
self._witness_utxo = self.utxo.outputs()[self.prevout.out_idx]

10
electrum/wallet.py

@ -2130,9 +2130,12 @@ class Abstract_Wallet(ABC, Logger, EventListener):
address: str = None,
ignore_network_issues: bool = True,
) -> None:
# We prefer to include UTXO (full tx) for every input.
# We cannot include UTXO if the prev tx is not signed yet though (chain of unsigned txs),
# in which case we might include a WITNESS_UTXO.
# - We prefer to include UTXO (full tx), even for segwit inputs (see #6198).
# - For witness v0 inputs, we include *both* UTXO and WITNESS_UTXO. UTXO is a strict superset,
# so this is redundant, but it is (implied to be) "expected" from bip-0174 (see #8039).
# Regardless, this might improve compatibility with some other software.
# - For witness v1, witness_utxo will be enough though (bip-0341 sighash fixes known prior issues).
# - We cannot include UTXO if the prev tx is not signed yet (chain of unsigned txs).
address = address or txin.address
if txin.witness_utxo is None and txin.is_segwit() and address:
received, spent = self.adb.get_addr_io(address)
@ -2142,7 +2145,6 @@ class Abstract_Wallet(ABC, Logger, EventListener):
txin.witness_utxo = TxOutput.from_address_and_value(address, txin_value)
if txin.utxo is None:
txin.utxo = self.get_input_tx(txin.prevout.txid.hex(), ignore_network_issues=ignore_network_issues)
txin.ensure_there_is_only_one_utxo()
def _learn_derivation_path_for_address_from_txinout(self, txinout: Union[PartialTxInput, PartialTxOutput],
address: str) -> bool:

Loading…
Cancel
Save