transaction: treat native segwit input with non-empty witness as complete
What changed, and why it matters
This commit fixes a bug where Electrum incorrectly treated finalized Bitcoin transactions as incomplete. Some wallet software (like Bitcoin Core and Sparrow) creates native SegWit transactions that omit an empty placeholder field Electrum expected. As a result, Electrum could wrongly refuse to broadcast or mishandle valid, already-signed transactions. The fix makes Electrum recognize these transactions as complete when the witness data is present.
Review related completeness checks (e.g., tx.is_complete()) to ensure no other code paths still require script_sig for native segwit inputs. Consider backporting to stable branches if users report failed broadcasts of PSBTs from Bitcoin Core/Sparrow.
Security signals we found
Logic error in transaction completeness detection
Potential denial of service / user funds stuck due to refusal to broadcast valid finalized transaction
Interoperability failure with Bitcoin Core and Sparrow PSBT output
Evidence from the diff
PartialTxInput.is_complete() previously required script_sig to be present for an input to be considered complete. For native segwit inputs, Bitcoin Core and Sparrow produce a final PSBT with an empty/absent final scriptSig and only the witness. The patch adds a check: if the input has a witness and is_native_segwit(), it is considered complete regardless of script_sig. A regression test with a real Bitcoin Core-finalized P2WPKH PSBT is added.
Changed components
electrum/transaction.pyPartialTxInput.is_complete()PSBT parsing and finalization flowInspect captured patch +11 / −0
### electrum/transaction.py
@@ -1942,6 +1942,8 @@ def is_complete(self) -> bool:
return True
if self.script_sig is not None and not self.is_segwit():
return True
+ if self.has_witness() and self.is_native_segwit():
+ return True
if desc := self.script_descriptor:
try:
desc.satisfy(allow_dummy=False, sigdata=self.sigs_ecdsa)
### tests/test_psbt.py
@@ -97,6 +97,15 @@ def test_valid_psbt__input_with_both_witness_utxo_and_nonwitness_utxo(self):
tx = tx_from_any(bytes.fromhex('70736274ff0100710100000001626bbbb7a4ad82dbf7f6bd64ac3f40d0e2695b606d7953f2802b9ea426ea080a0000000000fdffffff02a025260000000000160014e5bddbfee3883729b48fe3385216e64e6035f6eb585d720000000000160014dab37af8fefbbb31887a0a5f9b2698f4a7b45f6a1c3914000001011f8096980000000000160014dab37af8fefbbb31887a0a5f9b2698f4a7b45f6a0100fd200101000000000101197a89cff51096b9dd4214cdee0eb90cb27a25477e739521d728a679724042730100000000fdffffff048096980000000000160014dab37af8fefbbb31887a0a5f9b2698f4a7b45f6a80969800000000001976a91405a20074ef7eb42c7c6fcd4f499faa699742783288ac809698000000000017a914b808938a8007bc54509cd946944c479c0fa6554f87131b2c0400000000160014a04dfdb9a9aeac3b3fada6f43c2a66886186e2440247304402204f5dbb9dda65eab26179f1ca7c37c8baf028153815085dd1bbb2b826296e3b870220379fcd825742d6e2bdff772f347b629047824f289a5499a501033f6c3495594901210363c9c98740fe0455c646215cea9b13807b758791c8af7b74e62968bef57ff8ae1e391400000000'))
self.assertEqual(1, len(tx.inputs()))
+ def test_valid_psbt__finalized_native_segwit_input_without_final_scriptsig(self):
+ # Case: PSBT with one P2WPKH input, finalized, empty scriptSig (Bitcoin Core does this). see #10986
+ raw_psbt = '70736274ff01005201000000010d350cefa29138de18a2d63a93cffda63721b07a6ecfa80a902f9514104b55ca0000000000fdffffff012a4a824a00000000160014b869999d342a5d42d6dc7af1efc28456da40297ac80100000001011f807c814a00000000160014460fc70f208bffa9abf3ae4abbd2f629d9cdcf5901086b024730440220475bb55814a52ea1036919e4408218c693b8bf93637b9f54c821b5baa3b846e102207276ed7a79493142c11fb01808a4142bbdd525ae7bdccdf8ecb7b8e3c856b4d90121024cdeaca7a53a7e23a1edbe9260794eaa83063534b5f111ee3c67d8b0cb88f0ee0000'
+ tx = tx_from_any(raw_psbt)
+ self.assertEqual(1, len(tx.inputs()))
+ self.assertIsNone(tx.inputs()[0].script_sig)
+ self.assertTrue(tx.inputs()[0].is_complete())
+ self.assertTrue(tx.is_complete())
+
class TestInvalidPSBT(ElectrumTestCase):
# test cases from BIP-0174Why this scored 35/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.