@@ -429,6 +429,91 @@ func (a *AuxSweeper) signSweepVpackets(vPackets []*tappsbt.VPacket,
429429 return nil
430430}
431431
432+ // vPktsWithInput couples a vPkt along with the input that contained it.
433+ type vPktsWithInput struct {
434+ // btcInput is the Bitcoin that the vPkt will the spending from (on the
435+ // TAP layer).
436+ btcInput input.Input
437+
438+ // vPkts is the set of vPacket that will be used to spend the input.
439+ vPkts []* tappsbt.VPacket
440+
441+ // tapSigDesc houses the information we'll need to re-sign the vPackets
442+ // above. Note that this is only set if this is a second level packet.
443+ tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
444+ }
445+
446+ // isPresigned returns true if the vPktsWithInput is presigned. This will be the
447+ // for an HTLC spent directly from our local commitment transaction.
448+ func (v vPktsWithInput ) isPresigned () bool {
449+ witType := v .btcInput .WitnessType ()
450+ switch witType {
451+ case input .TaprootHtlcAcceptedLocalSuccess :
452+ return true
453+ case input .TaprootHtlcLocalOfferedTimeout :
454+ return true
455+ default :
456+ return false
457+ }
458+ }
459+
460+ // sweepVpkts contains the set of vPkts needed for sweeping an output. Most
461+ // outputs will only have the first level specified. The second level is needed
462+ // for HTLC outputs on our local commitment transaction.
463+ type sweepVpkts struct {
464+ // firstLevel houses vPackets that are used to sweep outputs directly
465+ // from the commitment transaction.
466+ firstLevel []vPktsWithInput
467+
468+ // secondLevel is used to sweep outputs that are created by second level
469+ // HTLC transactions.
470+ secondLevel []vPktsWithInput
471+ }
472+
473+ // firstLevelPkts returns a slice of the first level pkts.
474+ func (s sweepVpkts ) firstLevelPkts () []* tappsbt.VPacket {
475+ return fn .FlatMap (
476+ s .firstLevel , func (v vPktsWithInput ) []* tappsbt.VPacket {
477+ return v .vPkts
478+ },
479+ )
480+ }
481+
482+ // secondLevelPkts returns a slice of the second level pkts.
483+ func (s sweepVpkts ) secondLevelPkts () []* tappsbt.VPacket {
484+ return fn .FlatMap (
485+ s .secondLevel , func (v vPktsWithInput ) []* tappsbt.VPacket {
486+ return v .vPkts
487+ },
488+ )
489+ }
490+
491+ // allPkts returns a slice of both the first and second level pkts.
492+ func (s sweepVpkts ) allPkts () []* tappsbt.VPacket {
493+ return append (s .firstLevelPkts (), s .secondLevelPkts ()... )
494+ }
495+
496+ // allVpktsWithInput returns a slice of all vPktsWithInput.
497+ func (s sweepVpkts ) allVpktsWithInput () []vPktsWithInput {
498+ return append (s .firstLevel , s .secondLevel ... )
499+ }
500+
501+ // directSpendPkts returns the slice of all vPkts that are a direct spend from
502+ // the commitment transaction. This excludes vPkts that are the pre-signed 2nd
503+ // level transaction variant.
504+ func (s sweepVpkts ) directSpendPkts () []* tappsbt.VPacket {
505+ directSpends := lfn .Filter (func (vi vPktsWithInput ) bool {
506+ return ! vi .isPresigned ()
507+ }, s .allVpktsWithInput ())
508+ directPkts := fn .FlatMap (
509+ directSpends , func (v vPktsWithInput ) []* tappsbt.VPacket {
510+ return v .vPkts
511+ },
512+ )
513+
514+ return directPkts
515+ }
516+
432517// createAndSignSweepVpackets creates vPackets that sweep the funds from the
433518// channel to the wallet, and then signs them as well.
434519func (a * AuxSweeper ) createAndSignSweepVpackets (
@@ -640,6 +725,8 @@ func remoteHtlcTimeoutSweepDesc(keyRing *lnwallet.CommitmentKeyRing,
640725 return lfn.Err [tapscriptSweepDescs ](err )
641726 }
642727
728+ // TODO(roasbeef): use GenTaprootHtlcScript instead?
729+
643730 // Now that we have the script tree, we'll make the control block needed
644731 // to spend it, but taking the revoked path.
645732 ctrlBlock , err := htlcScriptTree .CtrlBlockForPath (
@@ -1222,8 +1309,8 @@ func importOutputProofs(scid lnwire.ShortChannelID,
12221309 spew .Sdump (inputProofLocator ))
12231310
12241311 // Before we combine the proofs below, we'll be sure to update
1225- // the transition proof to include the proper block+merkle
1226- // proof information.
1312+ // the transition proof to include the proper block+merkle proof
1313+ // information.
12271314 blockHash , err := chainBridge .GetBlockHash (
12281315 ctxb , int64 (scid .BlockHeight ),
12291316 )
@@ -1813,6 +1900,7 @@ func newBlobWithWitnessInfo(i input.Input) blobWithWitnessInfo {
18131900 )
18141901 switch i .WitnessType () {
18151902 // This is the case when we're sweeping the HTLC output on our local
1903+
18161904 // commitment transaction via a second level HTLC.
18171905 //
18181906 // The final witness stack is:
@@ -1868,40 +1956,106 @@ func newBlobWithWitnessInfo(i input.Input) blobWithWitnessInfo {
18681956 }
18691957}
18701958
1959+ // prepVpkts decodes the set of vPkts, supplementing them as needed to ensure
1960+ // all inputs can be swept properly.
1961+ func prepVpkts (bRes blobWithWitnessInfo ,
1962+ secondLevel bool ) (* vPktsWithInput , error ) {
1963+
1964+ var res cmsg.ContractResolution
1965+ err := res .Decode (bytes .NewReader (bRes .resolutionBlob ))
1966+ if err != nil {
1967+ return nil , err
1968+ }
1969+
1970+ // For each vPacket, if we have a preimage to insert, then we'll we'll
1971+ // update the witness to insert the preimage at the correct index.
1972+ var tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
1973+ pkts := res .Vpkts1 ()
1974+ if secondLevel {
1975+ pkts = res .Vpkts2 ()
1976+ tapSigDesc = res .SigDescs ()
1977+ }
1978+
1979+ err = lfn .MapOptionZ (bRes .preimageInfo , func (p preimageDesc ) error {
1980+ for _ , pkt := range pkts {
1981+ newAsset := pkt .Outputs [0 ].Asset
1982+
1983+ prevWitness := newAsset .PrevWitnesses [0 ].TxWitness
1984+ prevWitness = slices .Insert (
1985+ prevWitness , p .witnessIndex ,
1986+ p .preimage [:],
1987+ )
1988+ err := newAsset .UpdateTxWitness (0 , prevWitness )
1989+ if err != nil {
1990+ return err
1991+ }
1992+ }
1993+
1994+ return nil
1995+ })
1996+ if err != nil {
1997+ return nil , err
1998+ }
1999+
2000+ return & vPktsWithInput {
2001+ vPkts : pkts ,
2002+ btcInput : bRes .input ,
2003+ tapSigDesc : tapSigDesc ,
2004+ }, nil
2005+ }
2006+
18712007// extractInputVPackets extracts the vPackets from the inputs passed in. If
18722008// none of the inputs have any resolution blobs. Then an empty slice will be
18732009// returned.
1874- func extractInputVPackets (inputs []input.Input ) lfn.Result [[]* tappsbt.VPacket ] {
1875- type returnType = []* tappsbt.VPacket
1876-
1877- // Otherwise, we'll extract the set of resolution blobs from the inputs
2010+ func extractInputVPackets (inputs []input.Input ) lfn.Result [sweepVpkts ] {
2011+ // First, we'll extract the set of resolution blobs from the inputs
18782012 // passed in.
18792013 relevantInputs := fn .Filter (inputs , func (i input.Input ) bool {
18802014 return i .ResolutionBlob ().IsSome ()
18812015 })
1882- resolutionBlobs := fn .Map (relevantInputs , func (i input.Input ) tlv.Blob {
1883- // We already know this has a blob from the filter above.
1884- return i .ResolutionBlob ().UnwrapOr (nil )
1885- })
1886-
1887- // With our set of resolution inputs extracted, we'll now decode them
1888- // in the vPackets we'll use to generate the output to addr.
1889- vPkts , err := fn .FlatMapErr (
1890- resolutionBlobs ,
1891- func (b tlv.Blob ) ([]* tappsbt.VPacket , error ) {
1892- var res cmsg.ContractResolution
1893- if err := res .Decode (bytes .NewReader (b )); err != nil {
1894- return nil , err
1895- }
2016+ resolutionInfo := fn .Map (
2017+ relevantInputs , newBlobWithWitnessInfo ,
2018+ )
18962019
1897- return res .Vpkts1 (), nil
2020+ firstLevelSweeps := lfn .Filter (
2021+ func (info blobWithWitnessInfo ) bool {
2022+ return ! info .secondLevel
18982023 },
2024+ resolutionInfo ,
18992025 )
1900- if err != nil {
1901- return lfn.Err [returnType ](err )
2026+ secondLevelSweeps := lfn .Filter (
2027+ func (info blobWithWitnessInfo ) bool {
2028+ return info .secondLevel
2029+ },
2030+ resolutionInfo ,
2031+ )
2032+
2033+ // With our set of resolution inputs extracted, we'll now decode them in
2034+ // the vPackets we'll use to generate the output to addr.
2035+ var vPkts1 []vPktsWithInput
2036+ for _ , bRes := range firstLevelSweeps {
2037+ vpkt , err := prepVpkts (bRes , false )
2038+ if err != nil {
2039+ return lfn.Err [sweepVpkts ](err )
2040+ }
2041+
2042+ vPkts1 = append (vPkts1 , * vpkt )
19022043 }
19032044
1904- return lfn .Ok (vPkts )
2045+ var vPkts2 []vPktsWithInput
2046+ for _ , bRes := range secondLevelSweeps {
2047+ vpkt , err := prepVpkts (bRes , true )
2048+ if err != nil {
2049+ return lfn.Err [sweepVpkts ](err )
2050+ }
2051+
2052+ vPkts2 = append (vPkts2 , * vpkt )
2053+ }
2054+
2055+ return lfn .Ok (sweepVpkts {
2056+ firstLevel : vPkts1 ,
2057+ secondLevel : vPkts2 ,
2058+ })
19052059}
19062060
19072061// sweepContracts takes a set of inputs, and the change address we'd use to
@@ -1925,13 +2079,25 @@ func (a *AuxSweeper) sweepContracts(inputs []input.Input,
19252079
19262080 // Now that we know we have a relevant input set, extract all the
19272081 // vPackets from the inputs.
1928- vPkts , err := extractInputVPackets (inputs ).Unpack ()
2082+ sPkts , err := extractInputVPackets (inputs ).Unpack ()
19292083 if err != nil {
19302084 return lfn.Err [returnType ](err )
19312085 }
19322086
19332087 log .Infof ("Generating anchor output for vpkts=%v" ,
1934- limitSpewer .Sdump (vPkts ))
2088+ limitSpewer .Sdump (sPkts ))
2089+
2090+ // If this is a sweep from the local commitment transaction. Then we'll
2091+ // have both the first and second level sweeps. However for the first
2092+ // sweep, it's a broadcast of a pre-signed transaction, so we don't need
2093+ // an anchor output for those.
2094+ directPkts := sPkts .directSpendPkts ()
2095+
2096+ // If there're no direct level vPkts, then we can just return a nil
2097+ // error as we don't have a real sweep output to create.
2098+ if len (directPkts ) == 0 {
2099+ return lfn.Err [sweep.SweepOutput ](nil )
2100+ }
19352101
19362102 // At this point, now that we're about to generate a new output, we'll
19372103 // need an internal key, so we can update all the vPkts.
@@ -1944,17 +2110,34 @@ func (a *AuxSweeper) sweepContracts(inputs []input.Input,
19442110 if err != nil {
19452111 return lfn.Err [returnType ](err )
19462112 }
1947- for idx := range vPkts {
1948- for _ , vOut := range vPkts [idx ].Outputs {
2113+ for idx := range directPkts {
2114+ for _ , vOut := range directPkts [idx ].Outputs {
19492115 vOut .SetAnchorInternalKey (
19502116 internalKey , a .cfg .ChainParams .HDCoinType ,
19512117 )
19522118 }
19532119 }
19542120
2121+ // For any second level outputs we're sweeping, we'll need to sign for
2122+ // it, as now we know the txid of the sweeping transaction. We'll do
2123+ // this again when we register for the final broadcast, we we need to
2124+ // sign the right prevIDs.
2125+ for _ , sweepSet := range sPkts .secondLevel {
2126+ for _ , vPkt := range sweepSet .vPkts {
2127+ prevOut := sweepSet .btcInput .OutPoint ()
2128+ for _ , vIn := range vPkt .Inputs {
2129+ vIn .PrevID .OutPoint = prevOut
2130+ }
2131+ for _ , vOut := range vPkt .Outputs {
2132+ //nolint:lll
2133+ vOut .Asset .PrevWitnesses [0 ].PrevID .OutPoint = prevOut
2134+ }
2135+ }
2136+ }
2137+
19552138 // Now that we have our set of resolutions, we'll make a new commitment
19562139 // out of all the vPackets contained.
1957- outCommitments , err := tapsend .CreateOutputCommitments (vPkts )
2140+ outCommitments , err := tapsend .CreateOutputCommitments (directPkts )
19582141 if err != nil {
19592142 return lfn .Errf [returnType ]("unable to create " +
19602143 "output commitments: %w" , err )
@@ -2034,7 +2217,7 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20342217
20352218 // If we don't have any vPackets that had our resolution data in them,
20362219 // then we can exit early.
2037- if len (vPkts ) == 0 {
2220+ if len (vPkts . firstLevel ) == 0 && len ( vPkts . secondLevel ) == 0 {
20382221 log .Infof ("Sweep request had no vPkts, exiting" )
20392222 return nil
20402223 }
@@ -2057,16 +2240,16 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20572240
20582241 // We'll also use the passed in context to set the anchor key again for
20592242 // all the vOuts.
2060- for idx := range vPkts {
2061- for _ , vOut := range vPkts [idx ].Outputs {
2243+ for idx := range vPkts . firstLevelPkts () {
2244+ for _ , vOut := range vPkts . firstLevelPkts () [idx ].Outputs {
20622245 vOut .SetAnchorInternalKey (
20632246 internalKey , a .cfg .ChainParams .HDCoinType ,
20642247 )
20652248 }
20662249 }
20672250
20682251 // Now that we have our vPkts, we'll re-create the output commitments.
2069- outCommitments , err := tapsend .CreateOutputCommitments (vPkts )
2252+ outCommitments , err := tapsend .CreateOutputCommitments (vPkts . allPkts () )
20702253 if err != nil {
20712254 return fmt .Errorf ("unable to create output " +
20722255 "commitments: %w" , err )
@@ -2088,15 +2271,16 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20882271 //
20892272 // TODO(roasbeef): base off allocations? then can serialize, then
20902273 // re-use the logic
2091- for idx := range vPkts {
2092- vPkt := vPkts [idx ]
2274+ allVpkts := vPkts .allPkts ()
2275+ for idx := range allVpkts {
2276+ vPkt := allVpkts [idx ]
20932277 for outIdx := range vPkt .Outputs {
20942278 exclusionCreator := sweepExclusionProofGen (
20952279 changeInternalKey ,
20962280 )
20972281
20982282 proofSuffix , err := tapsend .CreateProofSuffixCustom (
2099- sweepTx , vPkt , outCommitments , outIdx , vPkts ,
2283+ sweepTx , vPkt , outCommitments , outIdx , allVpkts ,
21002284 exclusionCreator ,
21012285 )
21022286 if err != nil {
@@ -2116,7 +2300,7 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
21162300 // We pass false for the last arg as we already updated our suffix
21172301 // proofs here.
21182302 return shipChannelTxn (
2119- a .cfg .TxSender , sweepTx , outCommitments , vPkts , int64 (fee ),
2303+ a .cfg .TxSender , sweepTx , outCommitments , allVpkts , int64 (fee ),
21202304 )
21212305}
21222306
0 commit comments