@@ -430,6 +430,61 @@ func (a *AuxSweeper) signSweepVpackets(vPackets []*tappsbt.VPacket,
430430 return nil
431431}
432432
433+ // applySignDescToVIn couples a vPkt along with the input that contained it.
434+ type vPktsWithInput struct {
435+ // btcInput is the Bitcoin that the vPkt will the spending from (on the
436+ // TAP layer).
437+ btcInput input.Input
438+
439+ // vPkts is the set of vPacket that will be used to spend the input.
440+ vPkts []* tappsbt.VPacket
441+
442+ // tapsigDesc houses the information we'll need to re-sign the vPackets
443+ // above. Note that this is only set if this is a second level packet.
444+ tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
445+ }
446+
447+ // sweepVpkts contains the set of vPkts needed for sweeping an output. Most
448+ // outputs will only have the first level specified. The second level is needed
449+ // for HTLC outputs on our local commitment transaction.
450+ type sweepVpkts struct {
451+ // firstLevel houses vPackets that are used to sweep outputs directly
452+ // from the commitment transaction.
453+ firstLevel []vPktsWithInput
454+
455+ // secondLevel is used to sweep outputs that are created by second level
456+ // HTLC transactions.
457+ secondLevel []vPktsWithInput
458+ }
459+
460+ // isEmpty returns true if the sweepVpkts is empty.
461+ func (s sweepVpkts ) isEmpty () bool {
462+ return len (s .firstLevel ) == 0 && len (s .secondLevel ) == 0
463+ }
464+
465+ // firstLevelPkts returns a slice of the first level pkts.
466+ func (s sweepVpkts ) firstLevelPkts () []* tappsbt.VPacket {
467+ return fn .FlatMap (
468+ s .firstLevel , func (v vPktsWithInput ) []* tappsbt.VPacket {
469+ return v .vPkts
470+ },
471+ )
472+ }
473+
474+ // secondLevelPkts returns a slice of the second level pkts.
475+ func (s sweepVpkts ) secondLevelPkts () []* tappsbt.VPacket {
476+ return fn .FlatMap (
477+ s .secondLevel , func (v vPktsWithInput ) []* tappsbt.VPacket {
478+ return v .vPkts
479+ },
480+ )
481+ }
482+
483+ // allPkts returns a slice of both the first and second level pkts.
484+ func (s sweepVpkts ) allPkts () []* tappsbt.VPacket {
485+ return append (s .firstLevelPkts (), s .secondLevelPkts ()... )
486+ }
487+
433488// createAndSignSweepVpackets creates vPackets that sweep the funds from the
434489// channel to the wallet, and then signs them as well.
435490func (a * AuxSweeper ) createAndSignSweepVpackets (
@@ -1844,40 +1899,121 @@ func newBlobWithWitnessInfo(i input.Input) lfn.Result[blobWithWitnessInfo] {
18441899 })
18451900}
18461901
1902+ // prepVpkts decodes the set of vPkts, supplementing them as needed to ensure
1903+ // all inputs can be swept properly.
1904+ func prepVpkts (bRes lfn.Result [blobWithWitnessInfo ],
1905+ secondLevel bool ) (* vPktsWithInput , error ) {
1906+
1907+ b , err := bRes .Unpack ()
1908+ if err != nil {
1909+ return nil , err
1910+ }
1911+ var res cmsg.ContractResolution
1912+
1913+ err = res .Decode (bytes .NewReader (b .resolutionBlob ))
1914+ if err != nil {
1915+ return nil , err
1916+ }
1917+
1918+ // For each vPacket, if we have a preimage to insert, then we'll we'll
1919+ // update the witness to insert the preimage at the correct index.
1920+ var tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
1921+ pkts := res .Vpkts1 ()
1922+ if secondLevel {
1923+ pkts = res .Vpkts2 ()
1924+ }
1925+
1926+ b .preimageInfo .WhenSome (func (p preimageDesc ) {
1927+ vIns := fn .FlatMap (
1928+ pkts ,
1929+ func (vPkt * tappsbt.VPacket ) []* tappsbt.VInput {
1930+ return vPkt .Inputs
1931+ },
1932+ )
1933+
1934+ for _ , vIn := range vIns {
1935+ prevWitness := vIn .Asset ().PrevWitnesses [0 ].TxWitness
1936+ vIn .Asset ().PrevWitnesses [0 ].TxWitness = slices .Insert (
1937+ prevWitness , p .witnessIndex ,
1938+ p .preimage [:],
1939+ )
1940+ }
1941+ })
1942+
1943+ return & vPktsWithInput {
1944+ vPkts : pkts ,
1945+ btcInput : b .input ,
1946+ tapSigDesc : tapSigDesc ,
1947+ }, nil
1948+ }
1949+
18471950// extractInputVPackets extracts the vPackets from the inputs passed in. If
18481951// none of the inputs have any resolution blobs. Then an empty slice will be
18491952// returned.
1850- func extractInputVPackets (inputs []input.Input ) lfn.Result [[] * tappsbt. VPacket ] {
1851- type returnType = [] * tappsbt. VPacket
1953+ func extractInputVPackets (inputs []input.Input ) lfn.Result [sweepVpkts ] {
1954+ type returnType = sweepVpkts
18521955
18531956 // Otherwise, we'll extract the set of resolution blobs from the inputs
18541957 // passed in.
18551958 relevantInputs := fn .Filter (inputs , func (i input.Input ) bool {
18561959 return i .ResolutionBlob ().IsSome ()
18571960 })
1858- resolutionBlobs := fn .Map (relevantInputs , func (i input.Input ) tlv.Blob {
1859- // We already know this has a blob from the filter above.
1860- return i .ResolutionBlob ().UnwrapOr (nil )
1861- })
1961+ resolutionInfo := fn .Map (
1962+ relevantInputs ,
1963+ func (i input.Input ) lfn.Result [blobWithWitnessInfo ] {
1964+ return newBlobWithWitnessInfo (i )
1965+ },
1966+ )
18621967
1863- // With our set of resolution inputs extracted, we'll now decode them
1864- // in the vPackets we'll use to generate the output to addr.
1865- vPkts , err := fn .FlatMapErr (
1866- resolutionBlobs ,
1867- func (b tlv.Blob ) ([]* tappsbt.VPacket , error ) {
1868- var res cmsg.ContractResolution
1869- if err := res .Decode (bytes .NewReader (b )); err != nil {
1870- return nil , err
1871- }
1968+ firstLevelSweeps := lfn .Filter (
1969+ func (info lfn.Result [blobWithWitnessInfo ]) bool {
1970+ var secondLevel bool
1971+ info .WhenResult (func (i blobWithWitnessInfo ) {
1972+ secondLevel = i .secondLevel
1973+ })
18721974
1873- return res . Vpkts1 (), nil
1975+ return ! secondLevel
18741976 },
1977+ resolutionInfo ,
18751978 )
1876- if err != nil {
1877- return lfn.Err [returnType ](err )
1979+ secondLevelSweeps := lfn .Filter (
1980+ func (info lfn.Result [blobWithWitnessInfo ]) bool {
1981+ var secondLevel bool
1982+ info .WhenResult (func (i blobWithWitnessInfo ) {
1983+ secondLevel = i .secondLevel
1984+ })
1985+
1986+ return secondLevel
1987+ },
1988+ resolutionInfo ,
1989+ )
1990+
1991+ // With our set of resolution inputs extracted, we'll now decode them in
1992+ // the vPackets we'll use to generate the output to addr.
1993+ var vPkts1 []vPktsWithInput
1994+ for _ , bRes := range firstLevelSweeps {
1995+ vpkt , err := prepVpkts (bRes , false )
1996+ if err != nil {
1997+ return lfn.Err [sweepVpkts ](err )
1998+ }
1999+
2000+ vPkts1 = append (vPkts1 , * vpkt )
2001+ }
2002+
2003+ var vPkts2 []vPktsWithInput
2004+ for _ , bRes := range secondLevelSweeps {
2005+ vpkt , err := prepVpkts (bRes , true )
2006+ if err != nil {
2007+ return lfn.Err [sweepVpkts ](err )
2008+ }
2009+
2010+ vPkts2 = append (vPkts1 , * vpkt )
18782011 }
18792012
1880- return lfn .Ok (vPkts )
2013+ return lfn .Ok (sweepVpkts {
2014+ firstLevel : vPkts1 ,
2015+ secondLevel : vPkts2 ,
2016+ })
18812017}
18822018
18832019// sweepContracts takes a set of inputs, and the change address we'd use to
@@ -1901,13 +2037,24 @@ func (a *AuxSweeper) sweepContracts(inputs []input.Input,
19012037
19022038 // Now that we know we have a relevant input set, extract all the
19032039 // vPackets from the inputs.
1904- vPkts , err := extractInputVPackets (inputs ).Unpack ()
2040+ sPkts , err := extractInputVPackets (inputs ).Unpack ()
19052041 if err != nil {
19062042 return lfn.Err [returnType ](err )
19072043 }
19082044
19092045 log .Infof ("Generating anchor output for vpkts=%v" ,
1910- limitSpewer .Sdump (vPkts ))
2046+ limitSpewer .Sdump (sPkts ))
2047+
2048+ // Second level packets will already be anchored to the output assigned
2049+ // to it, so we only need to re-create the commitment for the first
2050+ // level outputs, which can be swept directly into the wallet.
2051+ firstLevelVpkts := sPkts .firstLevelPkts ()
2052+
2053+ // If there're no first level vPkts, then we can just return a nil error
2054+ // as we don't have a real sweep output to create.
2055+ if len (firstLevelVpkts ) == 0 {
2056+ return lfn.Err [sweep.SweepOutput ](nil )
2057+ }
19112058
19122059 // At this point, now that we're about to generate a new output, we'll
19132060 // need an internal key, so we can update all the vPkts.
@@ -1920,8 +2067,8 @@ func (a *AuxSweeper) sweepContracts(inputs []input.Input,
19202067 if err != nil {
19212068 return lfn.Err [returnType ](err )
19222069 }
1923- for idx := range vPkts {
1924- for _ , vOut := range vPkts [idx ].Outputs {
2070+ for idx := range firstLevelVpkts {
2071+ for _ , vOut := range firstLevelVpkts [idx ].Outputs {
19252072 vOut .SetAnchorInternalKey (
19262073 internalKey , a .cfg .ChainParams .HDCoinType ,
19272074 )
@@ -1930,7 +2077,7 @@ func (a *AuxSweeper) sweepContracts(inputs []input.Input,
19302077
19312078 // Now that we have our set of resolutions, we'll make a new commitment
19322079 // out of all the vPackets contained.
1933- outCommitments , err := tapsend .CreateOutputCommitments (vPkts )
2080+ outCommitments , err := tapsend .CreateOutputCommitments (firstLevelVpkts )
19342081 if err != nil {
19352082 return lfn .Errf [returnType ]("unable to create " +
19362083 "output commitments: %w" , err )
@@ -2010,7 +2157,7 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20102157
20112158 // If we don't have any vPackets that had our resolution data in them,
20122159 // then we can exit early.
2013- if len (vPkts ) == 0 {
2160+ if len (vPkts . firstLevel ) == 0 && len ( vPkts . secondLevel ) == 0 {
20142161 log .Infof ("Sweep request had no vPkts, exiting" )
20152162 return nil
20162163 }
@@ -2033,16 +2180,16 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20332180
20342181 // We'll also use the passed in context to set the anchor key again for
20352182 // all the vOuts.
2036- for idx := range vPkts {
2037- for _ , vOut := range vPkts [idx ].Outputs {
2183+ for idx := range vPkts . firstLevelPkts () {
2184+ for _ , vOut := range vPkts . firstLevelPkts () [idx ].Outputs {
20382185 vOut .SetAnchorInternalKey (
20392186 internalKey , a .cfg .ChainParams .HDCoinType ,
20402187 )
20412188 }
20422189 }
20432190
20442191 // Now that we have our vPkts, we'll re-create the output commitments.
2045- outCommitments , err := tapsend .CreateOutputCommitments (vPkts )
2192+ outCommitments , err := tapsend .CreateOutputCommitments (vPkts . allPkts () )
20462193 if err != nil {
20472194 return fmt .Errorf ("unable to create output " +
20482195 "commitments: %w" , err )
@@ -2064,15 +2211,16 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20642211 //
20652212 // TODO(roasbeef): base off allocations? then can serialize, then
20662213 // re-use the logic
2067- for idx := range vPkts {
2068- vPkt := vPkts [idx ]
2214+ allVpkts := vPkts .allPkts ()
2215+ for idx := range allVpkts {
2216+ vPkt := allVpkts [idx ]
20692217 for outIdx := range vPkt .Outputs {
20702218 exclusionCreator := sweepExclusionProofGen (
20712219 changeInternalKey ,
20722220 )
20732221
20742222 proofSuffix , err := tapsend .CreateProofSuffixCustom (
2075- sweepTx , vPkt , outCommitments , outIdx , vPkts ,
2223+ sweepTx , vPkt , outCommitments , outIdx , allVpkts ,
20762224 exclusionCreator ,
20772225 )
20782226 if err != nil {
@@ -2092,7 +2240,7 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
20922240 // We pass false for the last arg as we already updated our suffix
20932241 // proofs here.
20942242 return shipChannelTxn (
2095- a .cfg .TxSender , sweepTx , outCommitments , vPkts , int64 (fee ),
2243+ a .cfg .TxSender , sweepTx , outCommitments , allVpkts , int64 (fee ),
20962244 )
20972245}
20982246
0 commit comments