From 3e81cd1f1d22055380d8d093306c5d95e2b374e0 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Sun, 4 Feb 2024 00:14:59 +0000 Subject: [PATCH] trezor: fix regression in sign_transaction for trezor one for multisig fixes https://github.com/spesmilo/electrum/issues/8813 regression from https://github.com/spesmilo/electrum/commit/eef9680743e8a7ab6ad760c68ea63c396532bd65 We started setting the witness field in above commit to be able to provide the witnesses for already pre-signed external inputs to the device, e.g. for a coinjoin. Trezor One fw has pretty strict limits on the witness field: max 109 bytes, probably because that's a ~tight upper bound for a p2wpkh witness: , it comes out to 3+73(high-S and high-R)+33. https://github.com/trezor/trezor-firmware/blob/ed1785a985cc5a740b9b79b3dec7d6560db65179/legacy/firmware/protob/messages-bitcoin.options#L35 Trezor model T seems to have higher limits. tx_inputs is called for the tx being signed (for_sig=True), and for its parents/prev_txes (for_sig=False). The witness is only useful for the tx being signed, I think. Users reported seeing a "DataError: bytes overflow" exception when using a Trezor One to sign 2of3 p2wsh multisig txs. There were no external inputs involved so for the tx being signed all witnesses were None, however we were also setting the witness for the inputs of prev_txes. The witness for a 2of3 pw2sh multisig input is around ~253 bytes. To sidestep the problem, we now only set the witness in the for_sig=True case. Note that this means if someone tries to do a coinjoin with a Trezor One involving non-trivial external inputs, they will run into the same limit and exception. --- electrum/plugins/trezor/trezor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index ec2d95ba8..a25e98eee 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -365,10 +365,12 @@ class TrezorPlugin(HW_PluginBase): my_pubkey, full_path = keystore.find_my_pubkey_in_txinout(txin) if full_path: txinputtype.address_n = full_path + # Add witness if any. This is useful when signing a tx (for_sig=True) + # that has some already pre-signed external inputs. + txinputtype.witness = txin.witness txinputtype.amount = txin.value_sats() txinputtype.script_sig = txin.script_sig - txinputtype.witness = txin.witness txinputtype.sequence = txin.nsequence inputs.append(txinputtype)