@@ -432,6 +432,61 @@ func (a *AuxSweeper) signSweepVpackets(vPackets []*tappsbt.VPacket,
432432 return nil
433433}
434434
435+ // vPktsWithInput couples a vPkt along with the input that contained it.
436+ type vPktsWithInput struct {
437+ // btcInput is the Bitcoin that the vPkt will the spending from (on the
438+ // TAP layer).
439+ btcInput input.Input
440+
441+ // vPkts is the set of vPacket that will be used to spend the input.
442+ vPkts []* tappsbt.VPacket
443+
444+ // tapSigDesc houses the information we'll need to re-sign the vPackets
445+ // above. Note that this is only set if this is a second level packet.
446+ tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
447+ }
448+
449+ // sweepVpkts contains the set of vPkts needed for sweeping an output. Most
450+ // outputs will only have the first level specified. The second level is needed
451+ // for HTLC outputs on our local commitment transaction.
452+ type sweepVpkts struct {
453+ // firstLevel houses vPackets that are used to sweep outputs directly
454+ // from the commitment transaction.
455+ firstLevel []vPktsWithInput
456+
457+ // secondLevel is used to sweep outputs that are created by second level
458+ // HTLC transactions.
459+ secondLevel []vPktsWithInput
460+ }
461+
462+ // isEmpty returns true if the sweepVpkts is empty.
463+ func (s sweepVpkts ) isEmpty () bool {
464+ return len (s .firstLevel ) == 0 && len (s .secondLevel ) == 0
465+ }
466+
467+ // firstLevelPkts returns a slice of the first level pkts.
468+ func (s sweepVpkts ) firstLevelPkts () []* tappsbt.VPacket {
469+ return fn .FlatMap (
470+ s .firstLevel , func (v vPktsWithInput ) []* tappsbt.VPacket {
471+ return v .vPkts
472+ },
473+ )
474+ }
475+
476+ // secondLevelPkts returns a slice of the second level pkts.
477+ func (s sweepVpkts ) secondLevelPkts () []* tappsbt.VPacket {
478+ return fn .FlatMap (
479+ s .secondLevel , func (v vPktsWithInput ) []* tappsbt.VPacket {
480+ return v .vPkts
481+ },
482+ )
483+ }
484+
485+ // allPkts returns a slice of both the first and second level pkts.
486+ func (s sweepVpkts ) allPkts () []* tappsbt.VPacket {
487+ return append (s .firstLevelPkts (), s .secondLevelPkts ()... )
488+ }
489+
435490// createAndSignSweepVpackets creates vPackets that sweep the funds from the
436491// channel to the wallet, and then signs them as well.
437492func (a * AuxSweeper ) createAndSignSweepVpackets (
@@ -643,6 +698,8 @@ func remoteHtlcTimeoutSweepDesc(keyRing *lnwallet.CommitmentKeyRing,
643698 return lfn.Err [tapscriptSweepDescs ](err )
644699 }
645700
701+ // TODO(roasbeef): use GenTaprootHtlcScript instead?
702+
646703 // Now that we have the script tree, we'll make the control block needed
647704 // to spend it, but taking the revoked path.
648705 ctrlBlock , err := htlcScriptTree .CtrlBlockForPath (
@@ -1813,8 +1870,8 @@ func newBlobWithWitnessInfo(i input.Input) lfn.Result[blobWithWitnessInfo] {
18131870 secondLevel bool
18141871 )
18151872 switch i .WitnessType () {
1816-
18171873 // This is the case when we're sweeping the HTLC output on our local
1874+
18181875 // commitment transaction via a second level HTLC.
18191876 //
18201877 // The final witness stack is:
@@ -1874,40 +1931,118 @@ func newBlobWithWitnessInfo(i input.Input) lfn.Result[blobWithWitnessInfo] {
18741931 })
18751932}
18761933
1934+ // prepVpkts decodes the set of vPkts, supplementing them as needed to ensure
1935+ // all inputs can be swept properly.
1936+ func prepVpkts (bRes lfn.Result [blobWithWitnessInfo ],
1937+ secondLevel bool ) (* vPktsWithInput , error ) {
1938+
1939+ b , err := bRes .Unpack ()
1940+ if err != nil {
1941+ return nil , err
1942+ }
1943+
1944+ var res cmsg.ContractResolution
1945+ err = res .Decode (bytes .NewReader (b .resolutionBlob ))
1946+ if err != nil {
1947+ return nil , err
1948+ }
1949+
1950+ // For each vPacket, if we have a preimage to insert, then we'll we'll
1951+ // update the witness to insert the preimage at the correct index.
1952+ var tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
1953+ pkts := res .Vpkts1 ()
1954+ if secondLevel {
1955+ pkts = res .Vpkts2 ()
1956+ tapSigDesc = res .SigDescs ()
1957+ }
1958+
1959+ b .preimageInfo .WhenSome (func (p preimageDesc ) {
1960+ for _ , pkt := range pkts {
1961+ newAsset := pkt .Outputs [0 ].Asset
1962+
1963+ prevWitness := newAsset .PrevWitnesses [0 ].TxWitness
1964+ prevWitness = slices .Insert (
1965+ prevWitness , p .witnessIndex ,
1966+ p .preimage [:],
1967+ )
1968+ newAsset .UpdateTxWitness (0 , prevWitness )
1969+ }
1970+ })
1971+
1972+ return & vPktsWithInput {
1973+ vPkts : pkts ,
1974+ btcInput : b .input ,
1975+ tapSigDesc : tapSigDesc ,
1976+ }, nil
1977+ }
1978+
18771979// extractInputVPackets extracts the vPackets from the inputs passed in. If
18781980// none of the inputs have any resolution blobs. Then an empty slice will be
18791981// returned.
1880- func extractInputVPackets (inputs []input.Input ) lfn.Result [[] * tappsbt. VPacket ] {
1881- type returnType = [] * tappsbt. VPacket
1982+ func extractInputVPackets (inputs []input.Input ) lfn.Result [sweepVpkts ] {
1983+ type returnType = sweepVpkts
18821984
18831985 // Otherwise, we'll extract the set of resolution blobs from the inputs
18841986 // passed in.
18851987 relevantInputs := fn .Filter (inputs , func (i input.Input ) bool {
18861988 return i .ResolutionBlob ().IsSome ()
18871989 })
1888- resolutionBlobs := fn .Map (relevantInputs , func (i input.Input ) tlv.Blob {
1889- // We already know this has a blob from the filter above.
1890- return i .ResolutionBlob ().UnwrapOr (nil )
1891- })
1990+ resolutionInfo := fn .Map (
1991+ relevantInputs ,
1992+ func (i input.Input ) lfn.Result [blobWithWitnessInfo ] {
1993+ return newBlobWithWitnessInfo (i )
1994+ },
1995+ )
18921996
1893- // With our set of resolution inputs extracted, we'll now decode them
1894- // in the vPackets we'll use to generate the output to addr.
1895- vPkts , err := fn .FlatMapErr (
1896- resolutionBlobs ,
1897- func (b tlv.Blob ) ([]* tappsbt.VPacket , error ) {
1898- var res cmsg.ContractResolution
1899- if err := res .Decode (bytes .NewReader (b )); err != nil {
1900- return nil , err
1901- }
1997+ firstLevelSweeps := lfn .Filter (
1998+ func (info lfn.Result [blobWithWitnessInfo ]) bool {
1999+ var secondLevel bool
2000+ info .WhenResult (func (i blobWithWitnessInfo ) {
2001+ secondLevel = i .secondLevel
2002+ })
19022003
1903- return res . Vpkts1 (), nil
2004+ return ! secondLevel
19042005 },
2006+ resolutionInfo ,
19052007 )
1906- if err != nil {
1907- return lfn.Err [returnType ](err )
2008+ secondLevelSweeps := lfn .Filter (
2009+ func (info lfn.Result [blobWithWitnessInfo ]) bool {
2010+ var secondLevel bool
2011+ info .WhenResult (func (i blobWithWitnessInfo ) {
2012+ secondLevel = i .secondLevel
2013+ })
2014+
2015+ return secondLevel
2016+ },
2017+ resolutionInfo ,
2018+ )
2019+
2020+ // With our set of resolution inputs extracted, we'll now decode them in
2021+ // the vPackets we'll use to generate the output to addr.
2022+ var vPkts1 []vPktsWithInput
2023+ for _ , bRes := range firstLevelSweeps {
2024+ vpkt , err := prepVpkts (bRes , false )
2025+ if err != nil {
2026+ return lfn.Err [sweepVpkts ](err )
2027+ }
2028+
2029+ vPkts1 = append (vPkts1 , * vpkt )
19082030 }
19092031
1910- return lfn .Ok (vPkts )
2032+ var vPkts2 []vPktsWithInput
2033+ for _ , bRes := range secondLevelSweeps {
2034+ vpkt , err := prepVpkts (bRes , true )
2035+ if err != nil {
2036+ return lfn.Err [sweepVpkts ](err )
2037+ }
2038+
2039+ vPkts2 = append (vPkts2 , * vpkt )
2040+ }
2041+
2042+ return lfn .Ok (sweepVpkts {
2043+ firstLevel : vPkts1 ,
2044+ secondLevel : vPkts2 ,
2045+ })
19112046}
19122047
19132048// sweepContracts takes a set of inputs, and the change address we'd use to
@@ -1931,13 +2066,25 @@ func (a *AuxSweeper) sweepContracts(inputs []input.Input,
19312066
19322067 // Now that we know we have a relevant input set, extract all the
19332068 // vPackets from the inputs.
1934- vPkts , err := extractInputVPackets (inputs ).Unpack ()
2069+ sPkts , err := extractInputVPackets (inputs ).Unpack ()
19352070 if err != nil {
19362071 return lfn.Err [returnType ](err )
19372072 }
19382073
19392074 log .Infof ("Generating anchor output for vpkts=%v" ,
1940- limitSpewer .Sdump (vPkts ))
2075+ limitSpewer .Sdump (sPkts ))
2076+
2077+ // If this is a sweep from the local commitment transaction. Then we'll
2078+ // have both the first and second level sweeps. However for the first
2079+ // sweep, it's a broadcast of a pre-signed transaction, so we don't need
2080+ // an anchor output for those.
2081+ directPkts := sPkts .directSpendPkts ()
2082+
2083+ // If there're no direct level vPkts, then we can just return a nil
2084+ // error as we don't have a real sweep output to create.
2085+ if len (directPkts ) == 0 {
2086+ return lfn.Err [sweep.SweepOutput ](nil )
2087+ }
19412088
19422089 // At this point, now that we're about to generate a new output, we'll
19432090 // need an internal key, so we can update all the vPkts.
@@ -1950,17 +2097,32 @@ func (a *AuxSweeper) sweepContracts(inputs []input.Input,
19502097 if err != nil {
19512098 return lfn.Err [returnType ](err )
19522099 }
1953- for idx := range vPkts {
1954- for _ , vOut := range vPkts [idx ].Outputs {
2100+ for idx := range directPkts {
2101+ for _ , vOut := range directPkts [idx ].Outputs {
19552102 vOut .SetAnchorInternalKey (
19562103 internalKey , a .cfg .ChainParams .HDCoinType ,
19572104 )
19582105 }
19592106 }
19602107
2108+ // For any second level outputs we're sweeping, we'll need to sign for
2109+ // it, as now we know the txid of the sweeping transaction. We'll do
2110+ // this again when we register for the final broadcast, we we need to
2111+ // sign the right prevIDs.
2112+ for _ , sweepSet := range sPkts .secondLevel {
2113+ for _ , vPkt := range sweepSet .vPkts {
2114+ for _ , vIn := range vPkt .Inputs {
2115+ vIn .PrevID .OutPoint = sweepSet .btcInput .OutPoint ()
2116+ }
2117+ for _ , vOut := range vPkt .Outputs {
2118+ vOut .Asset .PrevWitnesses [0 ].PrevID .OutPoint = sweepSet .btcInput .OutPoint ()
2119+ }
2120+ }
2121+ }
2122+
19612123 // Now that we have our set of resolutions, we'll make a new commitment
19622124 // out of all the vPackets contained.
1963- outCommitments , err := tapsend .CreateOutputCommitments (vPkts )
2125+ outCommitments , err := tapsend .CreateOutputCommitments (directPkts )
19642126 if err != nil {
19652127 return lfn .Errf [returnType ]("unable to create " +
19662128 "output commitments: %w" , err )
@@ -2040,7 +2202,7 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20402202
20412203 // If we don't have any vPackets that had our resolution data in them,
20422204 // then we can exit early.
2043- if len (vPkts ) == 0 {
2205+ if len (vPkts . firstLevel ) == 0 && len ( vPkts . secondLevel ) == 0 {
20442206 log .Infof ("Sweep request had no vPkts, exiting" )
20452207 return nil
20462208 }
@@ -2063,16 +2225,16 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20632225
20642226 // We'll also use the passed in context to set the anchor key again for
20652227 // all the vOuts.
2066- for idx := range vPkts {
2067- for _ , vOut := range vPkts [idx ].Outputs {
2228+ for idx := range vPkts . firstLevelPkts () {
2229+ for _ , vOut := range vPkts . firstLevelPkts () [idx ].Outputs {
20682230 vOut .SetAnchorInternalKey (
20692231 internalKey , a .cfg .ChainParams .HDCoinType ,
20702232 )
20712233 }
20722234 }
20732235
20742236 // Now that we have our vPkts, we'll re-create the output commitments.
2075- outCommitments , err := tapsend .CreateOutputCommitments (vPkts )
2237+ outCommitments , err := tapsend .CreateOutputCommitments (vPkts . allPkts () )
20762238 if err != nil {
20772239 return fmt .Errorf ("unable to create output " +
20782240 "commitments: %w" , err )
@@ -2094,15 +2256,16 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20942256 //
20952257 // TODO(roasbeef): base off allocations? then can serialize, then
20962258 // re-use the logic
2097- for idx := range vPkts {
2098- vPkt := vPkts [idx ]
2259+ allVpkts := vPkts .allPkts ()
2260+ for idx := range allVpkts {
2261+ vPkt := allVpkts [idx ]
20992262 for outIdx := range vPkt .Outputs {
21002263 exclusionCreator := sweepExclusionProofGen (
21012264 changeInternalKey ,
21022265 )
21032266
21042267 proofSuffix , err := tapsend .CreateProofSuffixCustom (
2105- sweepTx , vPkt , outCommitments , outIdx , vPkts ,
2268+ sweepTx , vPkt , outCommitments , outIdx , allVpkts ,
21062269 exclusionCreator ,
21072270 )
21082271 if err != nil {
@@ -2122,7 +2285,7 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
21222285 // We pass false for the last arg as we already updated our suffix
21232286 // proofs here.
21242287 return shipChannelTxn (
2125- a .cfg .TxSender , sweepTx , outCommitments , vPkts , int64 (fee ),
2288+ a .cfg .TxSender , sweepTx , outCommitments , allVpkts , int64 (fee ),
21262289 )
21272290}
21282291
0 commit comments