@@ -446,6 +446,20 @@ type vPktsWithInput struct {
446446 tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
447447}
448448
449+ // isPresigned returns true if the vPktsWithInput is presigned. This will be the
450+ // for an HTLC spent directly from our local commitment transaction.
451+ func (v vPktsWithInput ) isPresigned () bool {
452+ witType := v .btcInput .WitnessType ()
453+ switch witType {
454+ case input .TaprootHtlcAcceptedLocalSuccess :
455+ return true
456+ case input .TaprootHtlcLocalOfferedTimeout :
457+ return true
458+ default :
459+ return false
460+ }
461+ }
462+
449463// sweepVpkts contains the set of vPkts needed for sweeping an output. Most
450464// outputs will only have the first level specified. The second level is needed
451465// for HTLC outputs on our local commitment transaction.
@@ -487,6 +501,27 @@ func (s sweepVpkts) allPkts() []*tappsbt.VPacket {
487501 return append (s .firstLevelPkts (), s .secondLevelPkts ()... )
488502}
489503
504+ // allVpktsWithInput returns a slice of all vPktsWithInput.
505+ func (s sweepVpkts ) allVpktsWithInput () []vPktsWithInput {
506+ return append (s .firstLevel , s .secondLevel ... )
507+ }
508+
509+ // directSpendPkts returns the slice of all vPkts that are a direct spend from
510+ // the commitment transaction. This excludes vPkts that are the pre-signed 2nd
511+ // level transaction variant.
512+ func (s sweepVpkts ) directSpendPkts () []* tappsbt.VPacket {
513+ directSpends := lfn .Filter (func (vi vPktsWithInput ) bool {
514+ return ! vi .isPresigned ()
515+ }, s .allVpktsWithInput ())
516+ directPkts := fn .FlatMap (
517+ directSpends , func (v vPktsWithInput ) []* tappsbt.VPacket {
518+ return v .vPkts
519+ },
520+ )
521+
522+ return directPkts
523+ }
524+
490525// createAndSignSweepVpackets creates vPackets that sweep the funds from the
491526// channel to the wallet, and then signs them as well.
492527func (a * AuxSweeper ) createAndSignSweepVpackets (
@@ -1726,6 +1761,7 @@ func (a *AuxSweeper) resolveContract(
17261761 default :
17271762 return lfn .Errf [returnType ]("unknown resolution type: %v" ,
17281763 req .Type )
1764+ // TODO(roasbeef): need to do HTLC revocation casesj:w
17291765 }
17301766
17311767 // The input proofs above were made originally using the fake commit tx
@@ -1980,6 +2016,7 @@ func prepVpkts(bRes lfn.Result[blobWithWitnessInfo],
19802016// none of the inputs have any resolution blobs. Then an empty slice will be
19812017// returned.
19822018func extractInputVPackets (inputs []input.Input ) lfn.Result [sweepVpkts ] {
2019+
19832020 type returnType = sweepVpkts
19842021
19852022 // Otherwise, we'll extract the set of resolution blobs from the inputs
@@ -2207,34 +2244,86 @@ func (a *AuxSweeper) registerAndBroadcastSweep(req *sweep.BumpRequest,
22072244 return nil
22082245 }
22092246
2210- ourSweepOutput , err := req .ExtraTxOut .UnwrapOrErr (
2211- fmt .Errorf ("extra tx out not populated" ),
2247+ // If this is a transaction that's only sweeping HTLC outputs via a
2248+ // pre-signed transaction, then we won't actually have an extra sweep
2249+ // output.
2250+ err = lfn .MapOptionZ (
2251+ req .ExtraTxOut ,
2252+ func (extraTxOut sweep.SweepOutput ) error {
2253+ ourSweepOutput , err := req .ExtraTxOut .UnwrapOrErr (
2254+ fmt .Errorf ("extra tx out not populated" ),
2255+ )
2256+ if err != nil {
2257+ return err
2258+ }
2259+ iKey , err := ourSweepOutput .InternalKey .UnwrapOrErr (
2260+ fmt .Errorf ("internal key not populated" ),
2261+ )
2262+ if err != nil {
2263+ return err
2264+ }
2265+
2266+ // We'll also use the passed in context to set the
2267+ // anchor key again for all the vOuts, but only for
2268+ // first level vPkts, as second level packets already
2269+ // commit to the internal key of the vOut.
2270+ vPkts := vPkts .directSpendPkts ()
2271+ for idx := range vPkts {
2272+ for _ , vOut := range vPkts [idx ].Outputs {
2273+ vOut .SetAnchorInternalKey (
2274+ iKey ,
2275+ a .cfg .ChainParams .HDCoinType ,
2276+ )
2277+ }
2278+ }
2279+
2280+ return nil
2281+ },
22122282 )
22132283 if err != nil {
22142284 return err
22152285 }
2216- internalKey , err := ourSweepOutput .InternalKey .UnwrapOrErr (
2217- fmt .Errorf ("internal key not populated" ),
2218- )
2219- if err != nil {
2220- return err
2286+
2287+ // For any second level outputs we're sweeping, we'll need to sign for
2288+ // it, as now we know the txid of the sweeping transaction.
2289+ for _ , sweepSet := range vPkts .secondLevel {
2290+ for _ , vPkt := range sweepSet .vPkts {
2291+ for _ , vIn := range vPkt .Inputs {
2292+ vIn .PrevID .OutPoint = sweepSet .btcInput .OutPoint ()
2293+ }
2294+
2295+ for _ , vOut := range vPkt .Outputs {
2296+ vOut .Asset .PrevWitnesses [0 ].PrevID .OutPoint = sweepSet .btcInput .OutPoint ()
2297+ }
2298+ }
22212299 }
22222300
2223- log .Infof ("Using %x for internal key: " ,
2224- internalKey .PubKey .SerializeCompressed ())
2301+ // If we have second level vPkts, then we'll need to sign them here, as
2302+ // now we know the input we're spending which was set above.
2303+ for _ , sweepSet := range vPkts .secondLevel {
2304+ tapSigDesc , err := sweepSet .tapSigDesc .UnwrapOrErr (
2305+ fmt .Errorf ("tap sig desc not populated" ),
2306+ )
2307+ if err != nil {
2308+ return err
2309+ }
22252310
2226- // We'll also use the passed in context to set the anchor key again for
2227- // all the vOuts.
2228- for idx := range vPkts .firstLevelPkts () {
2229- for _ , vOut := range vPkts .firstLevelPkts ()[idx ].Outputs {
2230- vOut .SetAnchorInternalKey (
2231- internalKey , a .cfg .ChainParams .HDCoinType ,
2232- )
2311+ err = a .signSweepVpackets (
2312+ sweepSet .vPkts , * sweepSet .btcInput .SignDesc (),
2313+ tapSigDesc .TapTweak .Val , tapSigDesc .CtrlBlock .Val ,
2314+ lfn .None [lnwallet.AuxSigDesc ](),
2315+ lfn .None [uint32 ](),
2316+ )
2317+ if err != nil {
2318+ return fmt .Errorf ("unable to sign second level " +
2319+ "vPkts: %w" , err )
22332320 }
22342321 }
22352322
22362323 // Now that we have our vPkts, we'll re-create the output commitments.
2237- outCommitments , err := tapsend .CreateOutputCommitments (vPkts .allPkts ())
2324+ outCommitments , err := tapsend .CreateOutputCommitments (
2325+ vPkts .allPkts (),
2326+ )
22382327 if err != nil {
22392328 return fmt .Errorf ("unable to create output " +
22402329 "commitments: %w" , err )
0 commit comments