diff --git a/contractcourt/breacharbiter.go b/contractcourt/breacharbiter.go index 10f49daa5..4ff90be81 100644 --- a/contractcourt/breacharbiter.go +++ b/contractcourt/breacharbiter.go @@ -1096,11 +1096,15 @@ func (bo *breachedOutput) SignDesc() *input.SignDescriptor { // sign descriptor. The method then returns the witness computed by invoking // this function on the first and subsequent calls. func (bo *breachedOutput) CraftInputScript(signer input.Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) (*input.Script, error) { + hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, + txinIdx int) (*input.Script, error) { // First, we ensure that the witness generation function has been // initialized for this breached output. - bo.witnessFunc = bo.witnessType.WitnessGenerator(signer, bo.SignDesc()) + signDesc := bo.SignDesc() + signDesc.PrevOutputFetcher = prevOutputFetcher + bo.witnessFunc = bo.witnessType.WitnessGenerator(signer, signDesc) // Now that we have ensured that the witness generation function has // been initialized, we can proceed to execute it and generate the @@ -1397,8 +1401,8 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64, // Compute the total amount contained in the inputs. var totalAmt btcutil.Amount - for _, input := range inputs { - totalAmt += btcutil.Amount(input.SignDesc().Output.Value) + for _, inp := range inputs { + totalAmt += btcutil.Amount(inp.SignDesc().Output.Value) } // We'll actually attempt to target inclusion within the next two @@ -1424,10 +1428,10 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64, // Next, we add all of the spendable outputs as inputs to the // transaction. - for _, input := range inputs { + for _, inp := range inputs { txn.AddTxIn(&wire.TxIn{ - PreviousOutPoint: *input.OutPoint(), - Sequence: input.BlocksToMaturity(), + PreviousOutPoint: *inp.OutPoint(), + Sequence: inp.BlocksToMaturity(), }) } @@ -1440,7 +1444,11 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64, // Create a sighash cache to improve the performance of hashing and // signing SigHashAll inputs. - hashCache := input.NewTxSigHashesV0Only(txn) + prevOutputFetcher, err := input.MultiPrevOutFetcher(inputs) + if err != nil { + return nil, err + } + hashCache := txscript.NewTxSigHashes(txn, prevOutputFetcher) // Create a closure that encapsulates the process of initializing a // particular output's witness generation function, computing the @@ -1452,7 +1460,7 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64, // transaction using the SpendableOutput's witness generation // function. inputScript, err := so.CraftInputScript( - b.cfg.Signer, txn, hashCache, idx, + b.cfg.Signer, txn, hashCache, prevOutputFetcher, idx, ) if err != nil { return err @@ -1467,8 +1475,8 @@ func (b *BreachArbiter) sweepSpendableOutputsTxn(txWeight int64, // Finally, generate a witness for each output and attach it to the // transaction. - for i, input := range inputs { - if err := addWitness(i, input); err != nil { + for i, inp := range inputs { + if err := addWitness(i, inp); err != nil { return nil, err } } @@ -1648,7 +1656,7 @@ func (ret *retributionInfo) Encode(w io.Writer) error { return nil } -// Dencode deserializes a retribution from the passed byte stream. +// Decode deserializes a retribution from the passed byte stream. func (ret *retributionInfo) Decode(r io.Reader) error { var scratch [32]byte diff --git a/contractcourt/breacharbiter_test.go b/contractcourt/breacharbiter_test.go index 7dae490ab..3cb16c084 100644 --- a/contractcourt/breacharbiter_test.go +++ b/contractcourt/breacharbiter_test.go @@ -1386,8 +1386,11 @@ func getSpendTransactions(signer input.Signer, chanPoint *wire.OutPoint, case input.HtlcAcceptedRevoke: fallthrough case input.HtlcOfferedRevoke: + cannedFetcher := txscript.NewCannedPrevOutputFetcher( + nil, 0, + ) inputScript, err := inp.CraftInputScript( - signer, htlcSweep, hashCache, 0, + signer, htlcSweep, hashCache, cannedFetcher, 0, ) if err != nil { return nil, err diff --git a/input/input.go b/input/input.go index 865a761a3..98ae2c056 100644 --- a/input/input.go +++ b/input/input.go @@ -42,6 +42,7 @@ type Input interface { // also nested p2sh outputs. CraftInputScript(signer Signer, txn *wire.MsgTx, hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (*Script, error) // BlocksToMaturity returns the relative timelock, as a number of @@ -221,9 +222,13 @@ func NewCsvInputWithCltv(outpoint *wire.OutPoint, witnessType WitnessType, // txIndex within the passed transaction. The input scripts generated by this // method support spending p2wkh, p2wsh, and also nested p2sh outputs. func (bi *BaseInput) CraftInputScript(signer Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) (*Script, error) { + hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (*Script, + error) { - witnessFunc := bi.witnessType.WitnessGenerator(signer, bi.SignDesc()) + signDesc := bi.SignDesc() + signDesc.PrevOutputFetcher = prevOutputFetcher + witnessFunc := bi.witnessType.WitnessGenerator(signer, signDesc) return witnessFunc(txn, hashCache, txinIdx) } @@ -260,11 +265,14 @@ func MakeHtlcSucceedInput(outpoint *wire.OutPoint, // txIndex within the passed transaction. The input scripts generated by this // method support spending p2wkh, p2wsh, and also nested p2sh outputs. func (h *HtlcSucceedInput) CraftInputScript(signer Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) (*Script, error) { + hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (*Script, + error) { desc := h.signDesc desc.SigHashes = hashCache desc.InputIndex = txinIdx + desc.PrevOutputFetcher = prevOutputFetcher witness, err := SenderHtlcSpendRedeem( signer, &desc, txn, h.preimage, @@ -291,7 +299,9 @@ type HtlcSecondLevelAnchorInput struct { // createWitness creates a witness allowing the passed transaction to // spend the input. createWitness func(signer Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) (wire.TxWitness, error) + hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, + txinIdx int) (wire.TxWitness, error) } // RequiredTxOut returns the tx out needed to be present on the sweep tx for @@ -313,9 +323,12 @@ func (i *HtlcSecondLevelAnchorInput) RequiredLockTime() (uint32, bool) { // method support spending p2wkh, p2wsh, and also nested p2sh outputs. func (i *HtlcSecondLevelAnchorInput) CraftInputScript(signer Signer, txn *wire.MsgTx, hashCache *txscript.TxSigHashes, - txinIdx int) (*Script, error) { + prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (*Script, + error) { - witness, err := i.createWitness(signer, txn, hashCache, txinIdx) + witness, err := i.createWitness( + signer, txn, hashCache, prevOutputFetcher, txinIdx, + ) if err != nil { return nil, err } @@ -335,11 +348,13 @@ func MakeHtlcSecondLevelTimeoutAnchorInput(signedTx *wire.MsgTx, // 2nd timeout transaction. createWitness := func(signer Signer, txn *wire.MsgTx, hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (wire.TxWitness, error) { desc := signDetails.SignDesc - desc.SigHashes = NewTxSigHashesV0Only(txn) + desc.SigHashes = txscript.NewTxSigHashes(txn, prevOutputFetcher) desc.InputIndex = txinIdx + desc.PrevOutputFetcher = prevOutputFetcher return SenderHtlcSpendTimeout( signDetails.PeerSig, signDetails.SigHashType, signer, @@ -373,11 +388,13 @@ func MakeHtlcSecondLevelSuccessAnchorInput(signedTx *wire.MsgTx, // success transaction. createWitness := func(signer Signer, txn *wire.MsgTx, hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, txinIdx int) (wire.TxWitness, error) { desc := signDetails.SignDesc desc.SigHashes = hashCache desc.InputIndex = txinIdx + desc.PrevOutputFetcher = prevOutputFetcher return ReceiverHtlcSpendRedeem( signDetails.PeerSig, signDetails.SigHashType, diff --git a/input/signdescriptor.go b/input/signdescriptor.go index bfcd50fe2..b97fbb5de 100644 --- a/input/signdescriptor.go +++ b/input/signdescriptor.go @@ -74,6 +74,11 @@ type SignDescriptor struct { // generating the final sighash for signing. SigHashes *txscript.TxSigHashes + // PrevOutputFetcher is an interface that can return the output + // information on all UTXOs that are being spent in this transaction. + // This MUST be set when spending Taproot outputs. + PrevOutputFetcher txscript.PrevOutputFetcher + // InputIndex is the target input within the transaction that should be // signed. InputIndex int diff --git a/input/taproot.go b/input/taproot.go index a80b51d29..e54628f7a 100644 --- a/input/taproot.go +++ b/input/taproot.go @@ -1,6 +1,8 @@ package input import ( + "fmt" + "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" ) @@ -18,3 +20,25 @@ func NewTxSigHashesV0Only(tx *wire.MsgTx) *txscript.TxSigHashes { nilFetcher := txscript.NewCannedPrevOutputFetcher(nil, 0) return txscript.NewTxSigHashes(tx, nilFetcher) } + +// MultiPrevOutFetcher returns a txscript.MultiPrevOutFetcher for the given set +// of inputs. +func MultiPrevOutFetcher(inputs []Input) (*txscript.MultiPrevOutFetcher, error) { + fetcher := txscript.NewMultiPrevOutFetcher(nil) + for _, inp := range inputs { + op := inp.OutPoint() + desc := inp.SignDesc() + + if op == nil { + return nil, fmt.Errorf("missing input outpoint") + } + + if desc == nil || desc.Output == nil { + return nil, fmt.Errorf("missing input utxo information") + } + + fetcher.AddPrevOut(*op, desc.Output) + } + + return fetcher, nil +} diff --git a/lnwallet/btcwallet/psbt.go b/lnwallet/btcwallet/psbt.go index 409277d22..ca19e1325 100644 --- a/lnwallet/btcwallet/psbt.go +++ b/lnwallet/btcwallet/psbt.go @@ -9,6 +9,7 @@ import ( "github.com/btcsuite/btcd/btcutil/psbt" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcwallet/waddrmgr" + "github.com/btcsuite/btcwallet/wallet" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet/chainfee" @@ -107,7 +108,8 @@ func (b *BtcWallet) SignPsbt(packet *psbt.Packet) error { // there are inputs that we don't know how to sign, we won't return any // error. So it's possible we're not the final signer. tx := packet.UnsignedTx - sigHashes := input.NewTxSigHashesV0Only(tx) + prevOutputFetcher := wallet.PsbtPrevOutputFetcher(packet) + sigHashes := txscript.NewTxSigHashes(tx, prevOutputFetcher) for idx := range tx.TxIn { in := packet.Inputs[idx] diff --git a/lnwallet/chanfunding/wallet_assembler.go b/lnwallet/chanfunding/wallet_assembler.go index 72cf56ce2..cc14dcac0 100644 --- a/lnwallet/chanfunding/wallet_assembler.go +++ b/lnwallet/chanfunding/wallet_assembler.go @@ -107,9 +107,15 @@ func (f *FullIntent) CompileFundingTx(extraInputs []*wire.TxIn, // Next, sign all inputs that are ours, collecting the signatures in // order of the inputs. + prevOutFetcher := NewSegWitV0DualFundingPrevOutputFetcher( + f.coinSource, extraInputs, + ) signDesc := input.SignDescriptor{ - HashType: txscript.SigHashAll, - SigHashes: input.NewTxSigHashesV0Only(fundingTx), + HashType: txscript.SigHashAll, + SigHashes: txscript.NewTxSigHashes( + fundingTx, prevOutFetcher, + ), + PrevOutputFetcher: prevOutFetcher, } for i, txIn := range fundingTx.TxIn { // We can only sign this input if it's ours, so we'll ask the @@ -374,3 +380,55 @@ func (w *WalletAssembler) FundingTxAvailable() {} // A compile-time assertion to ensure the WalletAssembler meets the // FundingTxAssembler interface. var _ FundingTxAssembler = (*WalletAssembler)(nil) + +// SegWitV0DualFundingPrevOutputFetcher is a txscript.PrevOutputFetcher that +// knows about local and remote funding inputs. +// +// TODO(guggero): Support dual funding with p2tr inputs, currently only segwit +// v0 inputs are supported. +type SegWitV0DualFundingPrevOutputFetcher struct { + local CoinSource + remote *txscript.MultiPrevOutFetcher +} + +var _ txscript.PrevOutputFetcher = (*SegWitV0DualFundingPrevOutputFetcher)(nil) + +// NewSegWitV0DualFundingPrevOutputFetcher creates a new +// txscript.PrevOutputFetcher from the given local and remote inputs. +// +// NOTE: Since the actual pkScript and amounts aren't passed in, this will just +// make sure that nothing will panic when creating a SegWit v0 sighash. But this +// code will NOT WORK for transactions that spend any Taproot inputs! +func NewSegWitV0DualFundingPrevOutputFetcher(localSource CoinSource, + remoteInputs []*wire.TxIn) txscript.PrevOutputFetcher { + + remote := txscript.NewMultiPrevOutFetcher(nil) + for _, inp := range remoteInputs { + // We add an empty output to prevent the sighash calculation + // from panicking. But this will always detect the inputs as + // SegWig v0! + remote.AddPrevOut(inp.PreviousOutPoint, &wire.TxOut{}) + } + return &SegWitV0DualFundingPrevOutputFetcher{ + local: localSource, + remote: remote, + } +} + +// FetchPrevOutput attempts to fetch the previous output referenced by the +// passed outpoint. +// +// NOTE: This is a part of the txscript.PrevOutputFetcher interface. +func (d *SegWitV0DualFundingPrevOutputFetcher) FetchPrevOutput( + op wire.OutPoint) *wire.TxOut { + + // Try the local source first. This will return nil if our internal + // wallet doesn't know the outpoint. + coin, err := d.local.CoinFromOutPoint(op) + if err == nil && coin != nil { + return &coin.TxOut + } + + // Fall back to the remote + return d.remote.FetchPrevOutput(op) +} diff --git a/lnwallet/rpcwallet/rpcwallet.go b/lnwallet/rpcwallet/rpcwallet.go index 052b3d86c..4871744e0 100644 --- a/lnwallet/rpcwallet/rpcwallet.go +++ b/lnwallet/rpcwallet/rpcwallet.go @@ -133,9 +133,11 @@ func (r *RPCKeyRing) SendOutputs(outputs []*wire.TxOut, // We know at this point that we only have inputs from our own wallet. // So we can just compute the input script using the remote signer. + outputFetcher := lnwallet.NewWalletPrevOutputFetcher(r.WalletController) signDesc := input.SignDescriptor{ - HashType: txscript.SigHashAll, - SigHashes: input.NewTxSigHashesV0Only(tx), + HashType: txscript.SigHashAll, + SigHashes: txscript.NewTxSigHashes(tx, outputFetcher), + PrevOutputFetcher: outputFetcher, } for i, txIn := range tx.TxIn { // We can only sign this input if it's ours, so we'll ask the @@ -579,6 +581,32 @@ func (r *RPCKeyRing) remoteSign(tx *wire.MsgTx, signDesc *input.SignDescriptor, return nil, fmt.Errorf("error converting TX into PSBT: %v", err) } + // We need to add witness information for all inputs! Otherwise, we'll + // have a problem when attempting to sign a taproot input! + for idx := range packet.Inputs { + // Skip the input we're signing for, that will get a special + // treatment later on. + if idx == signDesc.InputIndex { + continue + } + + txIn := tx.TxIn[idx] + info, err := r.WalletController.FetchInputInfo( + &txIn.PreviousOutPoint, + ) + if err != nil { + log.Warnf("No UTXO info found for index %d "+ + "(prev_outpoint=%v), won't be able to sign "+ + "for taproot output!", idx, + txIn.PreviousOutPoint) + continue + } + packet.Inputs[idx].WitnessUtxo = &wire.TxOut{ + Value: int64(info.Value), + PkScript: info.PkScript, + } + } + // Catch incorrect signing input index, just in case. if signDesc.InputIndex < 0 || signDesc.InputIndex >= len(packet.Inputs) { return nil, fmt.Errorf("invalid input index in sign descriptor") diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index e6145fae3..86eb1a920 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -2266,3 +2266,36 @@ func validateUpfrontShutdown(shutdown lnwire.DeliveryAddress, return false } } + +// WalletPrevOutputFetcher is a txscript.PrevOutputFetcher that can fetch +// outputs from a given wallet controller. +type WalletPrevOutputFetcher struct { + wc WalletController +} + +// A compile time assertion that WalletPrevOutputFetcher implements the +// txscript.PrevOutputFetcher interface. +var _ txscript.PrevOutputFetcher = (*WalletPrevOutputFetcher)(nil) + +// NewWalletPrevOutputFetcher creates a new WalletPrevOutputFetcher that fetches +// previous outputs from the given wallet controller. +func NewWalletPrevOutputFetcher(wc WalletController) *WalletPrevOutputFetcher { + return &WalletPrevOutputFetcher{ + wc: wc, + } +} + +// FetchPrevOutput attempts to fetch the previous output referenced by the +// passed outpoint. A nil value will be returned if the passed outpoint doesn't +// exist. +func (w *WalletPrevOutputFetcher) FetchPrevOutput(op wire.OutPoint) *wire.TxOut { + utxo, err := w.wc.FetchInputInfo(&op) + if err != nil { + return nil + } + + return &wire.TxOut{ + Value: int64(utxo.Value), + PkScript: utxo.PkScript, + } +} diff --git a/sweep/sweeper_test.go b/sweep/sweeper_test.go index 5ae22748d..a541ae6f5 100644 --- a/sweep/sweeper_test.go +++ b/sweep/sweeper_test.go @@ -1623,7 +1623,9 @@ func (i *testInput) RequiredTxOut() *wire.TxOut { // encode the spending outpoint and the tx input index as part of the returned // witness. func (i *testInput) CraftInputScript(_ input.Signer, txn *wire.MsgTx, - hashCache *txscript.TxSigHashes, txinIdx int) (*input.Script, error) { + hashCache *txscript.TxSigHashes, + prevOutputFetcher txscript.PrevOutputFetcher, + txinIdx int) (*input.Script, error) { // We'll encode the outpoint in the witness, so we can assert that the // expected input was signed at the correct index. diff --git a/sweep/txgenerator.go b/sweep/txgenerator.go index 3cbdb7c7b..76e959380 100644 --- a/sweep/txgenerator.go +++ b/sweep/txgenerator.go @@ -7,6 +7,7 @@ import ( "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnwallet" @@ -263,13 +264,18 @@ func createSweepTx(inputs []input.Input, outputs []*wire.TxOut, return nil, err } - hashCache := input.NewTxSigHashesV0Only(sweepTx) + prevInputFetcher, err := input.MultiPrevOutFetcher(inputs) + if err != nil { + return nil, fmt.Errorf("error creating prev input fetcher "+ + "for hash cache: %v", err) + } + hashCache := txscript.NewTxSigHashes(sweepTx, prevInputFetcher) // With all the inputs in place, use each output's unique input script // function to generate the final witness required for spending. addInputScript := func(idx int, tso input.Input) error { inputScript, err := tso.CraftInputScript( - signer, sweepTx, hashCache, idx, + signer, sweepTx, hashCache, prevInputFetcher, idx, ) if err != nil { return err diff --git a/watchtower/lookout/justice_descriptor.go b/watchtower/lookout/justice_descriptor.go index 5e21cda6b..dac18b048 100644 --- a/watchtower/lookout/justice_descriptor.go +++ b/watchtower/lookout/justice_descriptor.go @@ -2,6 +2,7 @@ package lookout import ( "errors" + "fmt" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcec/v2" @@ -177,11 +178,11 @@ func (p *JusticeDescriptor) assembleJusticeTxn(txWeight int64, // First, construct add the breached inputs to our justice transaction // and compute the total amount that will be swept. var totalAmt btcutil.Amount - for _, input := range inputs { - totalAmt += btcutil.Amount(input.txOut.Value) + for _, inp := range inputs { + totalAmt += btcutil.Amount(inp.txOut.Value) justiceTxn.AddTxIn(&wire.TxIn{ - PreviousOutPoint: input.outPoint, - Sequence: input.sequence, + PreviousOutPoint: inp.outPoint, + Sequence: inp.sequence, }) } @@ -217,20 +218,22 @@ func (p *JusticeDescriptor) assembleJusticeTxn(txWeight int64, } // Attach each of the provided witnesses to the transaction. - for _, input := range inputs { + prevOutFetcher, err := prevOutFetcher(inputs) + if err != nil { + return nil, fmt.Errorf("error creating previous output "+ + "fetcher: %v", err) + } + for _, inp := range inputs { // Lookup the input's new post-sort position. - i := inputIndex[input.outPoint] - justiceTxn.TxIn[i].Witness = input.witness + i := inputIndex[inp.outPoint] + justiceTxn.TxIn[i].Witness = inp.witness // Validate the reconstructed witnesses to ensure they are valid // for the breached inputs. vm, err := txscript.NewEngine( - input.txOut.PkScript, justiceTxn, i, + inp.txOut.PkScript, justiceTxn, i, txscript.StandardVerifyFlags, - nil, nil, input.txOut.Value, - txscript.NewCannedPrevOutputFetcher( - input.txOut.PkScript, input.txOut.Value, - ), + nil, nil, inp.txOut.Value, prevOutFetcher, ) if err != nil { return nil, err @@ -345,3 +348,20 @@ func buildWitness(witnessStack [][]byte, witnessScript []byte) [][]byte { return witness } + +// prevOutFetcher returns a txscript.MultiPrevOutFetcher for the given set +// of inputs. +func prevOutFetcher(inputs []*breachedInput) (*txscript.MultiPrevOutFetcher, + error) { + + fetcher := txscript.NewMultiPrevOutFetcher(nil) + for _, inp := range inputs { + if inp.txOut == nil { + return nil, fmt.Errorf("missing input utxo information") + } + + fetcher.AddPrevOut(inp.outPoint, inp.txOut) + } + + return fetcher, nil +} diff --git a/watchtower/wtclient/backup_task.go b/watchtower/wtclient/backup_task.go index 2ae836595..6f9d2082a 100644 --- a/watchtower/wtclient/backup_task.go +++ b/watchtower/wtclient/backup_task.go @@ -7,6 +7,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil/txsort" + "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/input" @@ -262,10 +263,14 @@ func (t *backupTask) craftSessionPayload( // information. This will either be contain both the to-local and // to-remote outputs, or only be the to-local output. inputs := t.inputs() - for prevOutPoint, input := range inputs { + prevOutputFetcher := txscript.NewMultiPrevOutFetcher(nil) + for prevOutPoint, inp := range inputs { + prevOutputFetcher.AddPrevOut( + prevOutPoint, inp.SignDesc().Output, + ) justiceTxn.AddTxIn(&wire.TxIn{ PreviousOutPoint: prevOutPoint, - Sequence: input.BlocksToMaturity(), + Sequence: inp.BlocksToMaturity(), }) } @@ -284,7 +289,7 @@ func (t *backupTask) craftSessionPayload( } // Construct a sighash cache to improve signing performance. - hashCache := input.NewTxSigHashesV0Only(justiceTxn) + hashCache := txscript.NewTxSigHashes(justiceTxn, prevOutputFetcher) // Since the transaction inputs could have been reordered as a result of // the BIP69 sort, create an index mapping each prevout to it's new @@ -303,7 +308,7 @@ func (t *backupTask) craftSessionPayload( // Construct the full witness required to spend this input. inputScript, err := inp.CraftInputScript( - signer, justiceTxn, hashCache, i, + signer, justiceTxn, hashCache, prevOutputFetcher, i, ) if err != nil { return hint, nil, err