From 9e2cccdbbdcd7dd67d197e49c1a09237e4bf7ff3 Mon Sep 17 00:00:00 2001 From: eugene Date: Thu, 22 Apr 2021 11:28:18 -0400 Subject: [PATCH 1/3] docs: add malleability note in psbt.md --- docs/psbt.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/psbt.md b/docs/psbt.md index e0c7c5baf..910d6d3a0 100644 --- a/docs/psbt.md +++ b/docs/psbt.md @@ -8,6 +8,10 @@ See [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) for a full description of the PSBT format and the different _roles_ that a participant in a PSBT can have. +To avoid possible malleability, all inputs to a funding transaction must be segwit +spends, meaning that P2PKH and normal P2SH cannot be used. An error will be +returned if any inputs are not segwit spends. + ## Creating/funding a PSBT The first step for every transaction that is constructed using a PSBT flow is to From b3f14d66f0423a8512d1c55e2b5233fc77425bd7 Mon Sep 17 00:00:00 2001 From: eugene Date: Thu, 22 Apr 2021 12:18:04 -0400 Subject: [PATCH 2/3] lnwallet/chanfunding: assert PSBT Inputs have WitnessUtxo --- lnwallet/chanfunding/psbt_assembler.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lnwallet/chanfunding/psbt_assembler.go b/lnwallet/chanfunding/psbt_assembler.go index 4d15ff53e..75b0e708d 100644 --- a/lnwallet/chanfunding/psbt_assembler.go +++ b/lnwallet/chanfunding/psbt_assembler.go @@ -249,6 +249,15 @@ func (i *PsbtIntent) Verify(packet *psbt.Packet) error { "output amount sum") } + // SumUtxoInputValues checks that packet.Inputs is non-empty. Here we + // check that each Input has a WitnessUtxo field, to avoid possible + // malleability. + for _, in := range packet.Inputs { + if in.WitnessUtxo == nil { + return fmt.Errorf("not all inputs are segwit spends") + } + } + i.PendingPsbt = packet i.State = PsbtVerified return nil From fa5627b779c2b80529fb844f5a54c13481d32ce0 Mon Sep 17 00:00:00 2001 From: eugene Date: Thu, 22 Apr 2021 12:19:12 -0400 Subject: [PATCH 3/3] lnwallet/chanfunding: non-segwit spend Verify test Also fixes error-handling in the Verify test when expectedErr == "" --- lnwallet/chanfunding/psbt_assembler_test.go | 39 ++++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/lnwallet/chanfunding/psbt_assembler_test.go b/lnwallet/chanfunding/psbt_assembler_test.go index cc40887ad..775f87cc5 100644 --- a/lnwallet/chanfunding/psbt_assembler_test.go +++ b/lnwallet/chanfunding/psbt_assembler_test.go @@ -340,8 +340,8 @@ func TestPsbtVerify(t *testing.T) { }, }, { - name: "input correct", - expectedErr: "", + name: "missing witness-utxo field", + expectedErr: "not all inputs are segwit spends", doVerify: func(amt int64, p *psbt.Packet, i *PsbtIntent) error { @@ -370,6 +370,33 @@ func TestPsbtVerify(t *testing.T) { return i.Verify(p) }, }, + { + name: "input correct", + expectedErr: "", + doVerify: func(amt int64, p *psbt.Packet, + i *PsbtIntent) error { + + txOut := &wire.TxOut{ + Value: int64(chanCapacity/2) + 1, + } + p.UnsignedTx.TxIn = []*wire.TxIn{ + {}, + { + PreviousOutPoint: wire.OutPoint{ + Index: 0, + }, + }, + } + p.Inputs = []psbt.PInput{ + { + WitnessUtxo: txOut, + }, + { + WitnessUtxo: txOut, + }} + return i.Verify(p) + }, + }, } // Create a simple assembler and ask it to provision a channel to get @@ -401,9 +428,11 @@ func TestPsbtVerify(t *testing.T) { } err = tc.doVerify(amt, pendingPsbt, psbtIntent) - if err != nil && tc.expectedErr != "" && - err.Error() != tc.expectedErr { - + if err != nil && tc.expectedErr == "" { + t.Fatalf("unexpected error, got '%v' wanted "+ + "'%v'", err, tc.expectedErr) + } + if err != nil && err.Error() != tc.expectedErr { t.Fatalf("unexpected error, got '%v' wanted "+ "'%v'", err, tc.expectedErr) }