diff --git a/lnwallet/chanfunding/psbt_assembler.go b/lnwallet/chanfunding/psbt_assembler.go index 9f82e0be..69c1c694 100644 --- a/lnwallet/chanfunding/psbt_assembler.go +++ b/lnwallet/chanfunding/psbt_assembler.go @@ -125,6 +125,11 @@ type PsbtIntent struct { // Only witness data should be added after the verification process. PendingPsbt *psbt.Packet + // FinalTX is the final, signed and ready to be published wire format + // transaction. This is only set after the PsbtFinalize step was + // completed successfully. + FinalTX *wire.MsgTx + // PsbtReady is an error channel the funding manager will listen for // a signal about the PSBT being ready to continue the funding flow. In // the normal, happy flow, this channel is only ever closed. If a @@ -270,12 +275,29 @@ func (i *PsbtIntent) Finalize(packet *psbt.Packet) error { if err != nil { return fmt.Errorf("error finalizing PSBT: %v", err) } - _, err = psbt.Extract(packet) + rawTx, err := psbt.Extract(packet) if err != nil { return fmt.Errorf("unable to extract funding TX: %v", err) } - // Do a basic check that this is still the same PSBT that we verified in + return i.FinalizeRawTX(rawTx) +} + +// FinalizeRawTX makes sure the final raw transaction that is given to the +// intent is fully valid and signed but still contains the same UTXOs and +// outputs as the pending transaction we previously verified. If everything +// checks out, the funding manager is informed that the channel can now be +// opened and the funding transaction be broadcast. +func (i *PsbtIntent) FinalizeRawTX(rawTx *wire.MsgTx) error { + if rawTx == nil { + return fmt.Errorf("raw transaction is nil") + } + if i.State != PsbtVerified { + return fmt.Errorf("invalid state. got %v expected %v", i.State, + PsbtVerified) + } + + // Do a basic check that this is still the same TX that we verified in // the previous step. This is to protect the user from unwanted // modifications. We only check the outputs and previous outpoints of // the inputs of the wire transaction because the fields in the PSBT @@ -283,23 +305,21 @@ func (i *PsbtIntent) Finalize(packet *psbt.Packet) error { if i.PendingPsbt == nil { return fmt.Errorf("PSBT was not verified first") } - err = verifyOutputsEqual( - packet.UnsignedTx.TxOut, i.PendingPsbt.UnsignedTx.TxOut, - ) + err := verifyOutputsEqual(rawTx.TxOut, i.PendingPsbt.UnsignedTx.TxOut) if err != nil { return fmt.Errorf("outputs differ from verified PSBT: %v", err) } err = verifyInputPrevOutpointsEqual( - packet.UnsignedTx.TxIn, i.PendingPsbt.UnsignedTx.TxIn, + rawTx.TxIn, i.PendingPsbt.UnsignedTx.TxIn, ) if err != nil { return fmt.Errorf("inputs differ from verified PSBT: %v", err) } - // As far as we can tell, this PSBT is ok to be used as a funding + // As far as we can tell, this TX is ok to be used as a funding // transaction. - i.PendingPsbt = packet i.State = PsbtFinalized + i.FinalTX = rawTx // Signal the funding manager that it can now finally continue with its // funding flow as the PSBT is now ready to be converted into a real @@ -319,32 +339,22 @@ func (i *PsbtIntent) CompileFundingTx() (*wire.MsgTx, error) { i.State, PsbtFinalized) } - // Make sure the PSBT can be finalized and extracted. - err := psbt.MaybeFinalizeAll(i.PendingPsbt) - if err != nil { - return nil, fmt.Errorf("error finalizing PSBT: %v", err) - } - fundingTx, err := psbt.Extract(i.PendingPsbt) - if err != nil { - return nil, fmt.Errorf("unable to extract funding TX: %v", err) - } - // Identify our funding outpoint now that we know everything's ready. _, txOut, err := i.FundingOutput() if err != nil { return nil, fmt.Errorf("cannot get funding output: %v", err) } - ok, idx := input.FindScriptOutputIndex(fundingTx, txOut.PkScript) + ok, idx := input.FindScriptOutputIndex(i.FinalTX, txOut.PkScript) if !ok { return nil, fmt.Errorf("funding output not found in PSBT") } i.chanPoint = &wire.OutPoint{ - Hash: fundingTx.TxHash(), + Hash: i.FinalTX.TxHash(), Index: idx, } i.State = PsbtFundingTxCompiled - return fundingTx, nil + return i.FinalTX, nil } // RemoteCanceled informs the listener of the PSBT ready channel that the