@@ -726,9 +726,14 @@ func commitRevokeSweepDesc(keyRing *lnwallet.CommitmentKeyRing,
726726
727727// remoteHtlcTimeoutSweepDesc creates a sweep desc for an HTLC output that is
728728// close to timing out on the remote party's commitment transaction.
729- func remoteHtlcTimeoutSweepDesc (keyRing * lnwallet.CommitmentKeyRing ,
729+ func remoteHtlcTimeoutSweepDesc (originalKeyRing * lnwallet.CommitmentKeyRing ,
730730 payHash []byte , csvDelay uint32 , htlcExpiry uint32 ,
731- ) lfn.Result [tapscriptSweepDescs ] {
731+ index input.HtlcIndex ) lfn.Result [tapscriptSweepDescs ] {
732+
733+ // We're sweeping an HTLC output, which has a tweaked script key. To be
734+ // able to create the correct control block, we need to tweak the key
735+ // ring with the index of the HTLC.
736+ keyRing := TweakedKeyRing (originalKeyRing , index )
732737
733738 // We're sweeping a timed out HTLC, which means that we'll need to
734739 // create the receiver's HTLC script tree (from the remote party's PoV).
@@ -769,8 +774,14 @@ func remoteHtlcTimeoutSweepDesc(keyRing *lnwallet.CommitmentKeyRing,
769774// remoteHtlcSuccessSweepDesc creates a sweep desc for an HTLC output present on
770775// the remote party's commitment transaction that we can sweep with the
771776// preimage.
772- func remoteHtlcSuccessSweepDesc (keyRing * lnwallet.CommitmentKeyRing ,
773- payHash []byte , csvDelay uint32 ) lfn.Result [tapscriptSweepDescs ] {
777+ func remoteHtlcSuccessSweepDesc (originalKeyRing * lnwallet.CommitmentKeyRing ,
778+ payHash []byte , csvDelay uint32 ,
779+ index input.HtlcIndex ) lfn.Result [tapscriptSweepDescs ] {
780+
781+ // We're sweeping an HTLC output, which has a tweaked script key. To be
782+ // able to create the correct control block, we need to tweak the key
783+ // ring with the index of the HTLC.
784+ keyRing := TweakedKeyRing (originalKeyRing , index )
774785
775786 // We're planning on sweeping an HTLC that we know the preimage to,
776787 // which the remote party sent, so we'll construct the sender version of
@@ -810,7 +821,7 @@ func remoteHtlcSuccessSweepDesc(keyRing *lnwallet.CommitmentKeyRing,
810821// present on our local commitment transaction. These are second level HTLCs, so
811822// we'll need to perform two stages of sweeps.
812823func localHtlcTimeoutSweepDesc (req lnwallet.ResolutionReq ,
813- ) lfn.Result [tapscriptSweepDescs ] {
824+ index input. HtlcIndex ) lfn.Result [tapscriptSweepDescs ] {
814825
815826 isIncoming := false
816827
@@ -827,11 +838,29 @@ func localHtlcTimeoutSweepDesc(req lnwallet.ResolutionReq,
827838 return lfn.Err [tapscriptSweepDescs ](err )
828839 }
829840
841+ // We're sweeping an HTLC output, which has a tweaked script key. To be
842+ // able to create the correct control block, we need to tweak the key
843+ // ring with the index of the HTLC.
844+ keyRing := TweakedKeyRing (req .KeyRing , index )
845+
846+ // We also need to overwrite the single tweak in the sign desc with the
847+ // tweak for this HTLC.
848+ sigDesc , err := req .AuxSigDesc .UnwrapOrErr (
849+ fmt .Errorf ("no aux sig desc for local HTLC success" ),
850+ )
851+ if err != nil {
852+ return lfn.Err [tapscriptSweepDescs ](err )
853+ }
854+ sigDesc .SignDetails .SignDesc .SingleTweak = AddTweakWithIndex (
855+ sigDesc .SignDetails .SignDesc .SingleTweak , index ,
856+ )
857+ req .AuxSigDesc = lfn .Some (sigDesc )
858+
830859 // We'll need to complete the control block to spend the second-level
831860 // HTLC, so first we'll make the script tree for the HTLC.
832861 htlcScriptTree , err := lnwallet .GenTaprootHtlcScript (
833- isIncoming , lntypes .Local , htlcExpiry ,
834- payHash , req . KeyRing , lfn .None [txscript.TapLeaf ](),
862+ isIncoming , lntypes .Local , htlcExpiry , payHash , keyRing ,
863+ lfn .None [txscript.TapLeaf ](),
835864 )
836865 if err != nil {
837866 return lfn .Errf [tapscriptSweepDescs ]("error creating " +
@@ -862,8 +891,8 @@ func localHtlcTimeoutSweepDesc(req lnwallet.ResolutionReq,
862891 // As this is an HTLC on our local commitment transaction, we'll also
863892 // need to generate a sweep desc for second level HTLC.
864893 secondLevelScriptTree , err := input .TaprootSecondLevelScriptTree (
865- req . KeyRing . RevocationKey , req . KeyRing . ToLocalKey ,
866- req . CommitCsvDelay , lfn .None [txscript.TapLeaf ](),
894+ keyRing . RevocationKey , keyRing . ToLocalKey , req . CommitCsvDelay ,
895+ lfn .None [txscript.TapLeaf ](),
867896 )
868897 if err != nil {
869898 return lfn .Errf [tapscriptSweepDescs ]("error " +
@@ -903,7 +932,7 @@ func localHtlcTimeoutSweepDesc(req lnwallet.ResolutionReq,
903932// present on our local commitment transaction that we can sweep with a
904933// preimage. These sweeps take two stages, so we'll add that extra information.
905934func localHtlcSucessSweepDesc (req lnwallet.ResolutionReq ,
906- ) lfn.Result [tapscriptSweepDescs ] {
935+ index input. HtlcIndex ) lfn.Result [tapscriptSweepDescs ] {
907936
908937 isIncoming := true
909938
@@ -920,11 +949,29 @@ func localHtlcSucessSweepDesc(req lnwallet.ResolutionReq,
920949 return lfn.Err [tapscriptSweepDescs ](err )
921950 }
922951
952+ // We're sweeping an HTLC output, which has a tweaked script key. To be
953+ // able to create the correct control block, we need to tweak the key
954+ // ring with the index of the HTLC.
955+ keyRing := TweakedKeyRing (req .KeyRing , index )
956+
957+ // We also need to overwrite the single tweak in the sign desc with the
958+ // tweak for this HTLC.
959+ sigDesc , err := req .AuxSigDesc .UnwrapOrErr (
960+ fmt .Errorf ("no aux sig desc for local HTLC success" ),
961+ )
962+ if err != nil {
963+ return lfn.Err [tapscriptSweepDescs ](err )
964+ }
965+ sigDesc .SignDetails .SignDesc .SingleTweak = AddTweakWithIndex (
966+ sigDesc .SignDetails .SignDesc .SingleTweak , index ,
967+ )
968+ req .AuxSigDesc = lfn .Some (sigDesc )
969+
923970 // We'll need to complete the control block to spend the second-level
924971 // HTLC, so first we'll make the script tree for the HTLC.
925972 htlcScriptTree , err := lnwallet .GenTaprootHtlcScript (
926973 isIncoming , lntypes .Local , htlcExpiry ,
927- payHash , req . KeyRing , lfn .None [txscript.TapLeaf ](),
974+ payHash , keyRing , lfn .None [txscript.TapLeaf ](),
928975 )
929976 if err != nil {
930977 return lfn .Errf [tapscriptSweepDescs ]("error creating " +
@@ -959,8 +1006,8 @@ func localHtlcSucessSweepDesc(req lnwallet.ResolutionReq,
9591006 // As this is an HTLC on our local commitment transaction, we'll also
9601007 // need to generate a sweep desc for second level HTLC.
9611008 secondLevelScriptTree , err := input .TaprootSecondLevelScriptTree (
962- req . KeyRing . RevocationKey , req . KeyRing . ToLocalKey ,
963- req . CommitCsvDelay , lfn .None [txscript.TapLeaf ](),
1009+ keyRing . RevocationKey , keyRing . ToLocalKey , req . CommitCsvDelay ,
1010+ lfn .None [txscript.TapLeaf ](),
9641011 )
9651012 if err != nil {
9661013 return lfn .Errf [tapscriptSweepDescs ]("error " +
@@ -1706,10 +1753,9 @@ func (a *AuxSweeper) resolveContract(
17061753 // assets for the remote party, which are actually the HTLCs we
17071754 // sent outgoing. We only care about this particular HTLC, so
17081755 // we'll filter out the rest.
1756+ htlcID := req .HtlcID .UnwrapOr (math .MaxUint64 )
17091757 htlcOutputs := commitState .OutgoingHtlcAssets .Val
1710- assetOutputs = htlcOutputs .FilterByHtlcIndex (
1711- req .HtlcID .UnwrapOr (math .MaxUint64 ),
1712- )
1758+ assetOutputs = htlcOutputs .FilterByHtlcIndex (htlcID )
17131759
17141760 payHash , err := req .PayHash .UnwrapOrErr (errNoPayHash )
17151761 if err != nil {
@@ -1720,7 +1766,7 @@ func (a *AuxSweeper) resolveContract(
17201766 // sweep desc for the timeout txn.
17211767 sweepDesc = remoteHtlcTimeoutSweepDesc (
17221768 req .KeyRing , payHash [:], req .CsvDelay ,
1723- req .CltvDelay .UnwrapOr (0 ),
1769+ req .CltvDelay .UnwrapOr (0 ), htlcID ,
17241770 )
17251771
17261772 // The remote party broadcasted a commitment transaction which held an
@@ -1729,10 +1775,9 @@ func (a *AuxSweeper) resolveContract(
17291775 // In this case, it's an outgoing HTLC from the PoV of the
17301776 // remote party, which is incoming for us. We'll only sweep this
17311777 // HTLC, so we'll filter out the rest.
1778+ htlcID := req .HtlcID .UnwrapOr (math .MaxUint64 )
17321779 htlcOutputs := commitState .IncomingHtlcAssets .Val
1733- assetOutputs = htlcOutputs .FilterByHtlcIndex (
1734- req .HtlcID .UnwrapOr (math .MaxUint64 ),
1735- )
1780+ assetOutputs = htlcOutputs .FilterByHtlcIndex (htlcID )
17361781
17371782 payHash , err := req .PayHash .UnwrapOrErr (errNoPayHash )
17381783 if err != nil {
@@ -1742,7 +1787,7 @@ func (a *AuxSweeper) resolveContract(
17421787 // Now that we know which output we'll be sweeping, we'll make a
17431788 // sweep desc for the timeout txn.
17441789 sweepDesc = remoteHtlcSuccessSweepDesc (
1745- req .KeyRing , payHash [:], req .CsvDelay ,
1790+ req .KeyRing , payHash [:], req .CsvDelay , htlcID ,
17461791 )
17471792
17481793 // In this case, we broadcast a commitment transaction which held an
@@ -1752,14 +1797,13 @@ func (a *AuxSweeper) resolveContract(
17521797 case input .TaprootHtlcLocalOfferedTimeout :
17531798 // Like the other HTLC cases, there's only a single output we
17541799 // care about here.
1800+ htlcID := req .HtlcID .UnwrapOr (math .MaxUint64 )
17551801 htlcOutputs := commitState .OutgoingHtlcAssets .Val
1756- assetOutputs = htlcOutputs .FilterByHtlcIndex (
1757- req .HtlcID .UnwrapOr (math .MaxUint64 ),
1758- )
1802+ assetOutputs = htlcOutputs .FilterByHtlcIndex (htlcID )
17591803
17601804 // With the output and pay desc located, we'll now create the
17611805 // sweep desc.
1762- sweepDesc = localHtlcTimeoutSweepDesc (req )
1806+ sweepDesc = localHtlcTimeoutSweepDesc (req , htlcID )
17631807
17641808 needsSecondLevel = true
17651809
@@ -1768,14 +1812,13 @@ func (a *AuxSweeper) resolveContract(
17681812 // needed to sweep both this output, as well as the second level
17691813 // output it creates.
17701814 case input .TaprootHtlcAcceptedLocalSuccess :
1815+ htlcID := req .HtlcID .UnwrapOr (math .MaxUint64 )
17711816 htlcOutputs := commitState .IncomingHtlcAssets .Val
1772- assetOutputs = htlcOutputs .FilterByHtlcIndex (
1773- req .HtlcID .UnwrapOr (math .MaxUint64 ),
1774- )
1817+ assetOutputs = htlcOutputs .FilterByHtlcIndex (htlcID )
17751818
17761819 // With the output and pay desc located, we'll now create the
17771820 // sweep desc.
1778- sweepDesc = localHtlcSucessSweepDesc (req )
1821+ sweepDesc = localHtlcSucessSweepDesc (req , htlcID )
17791822
17801823 needsSecondLevel = true
17811824
@@ -2573,3 +2616,22 @@ func (a *AuxSweeper) NotifyBroadcast(req *sweep.BumpRequest,
25732616
25742617 return resp
25752618}
2619+
2620+ // TweakedKeyRing returns a new commitment key ring with the revocation key
2621+ // tweaked by the given HTLC index.
2622+ func TweakedKeyRing (keyRing * lnwallet.CommitmentKeyRing ,
2623+ index input.HtlcIndex ) * lnwallet.CommitmentKeyRing {
2624+
2625+ return & lnwallet.CommitmentKeyRing {
2626+ CommitPoint : keyRing .CommitPoint ,
2627+ LocalCommitKeyTweak : keyRing .LocalCommitKeyTweak ,
2628+ LocalHtlcKeyTweak : keyRing .LocalHtlcKeyTweak ,
2629+ LocalHtlcKey : keyRing .LocalHtlcKey ,
2630+ RemoteHtlcKey : keyRing .RemoteHtlcKey ,
2631+ ToLocalKey : keyRing .ToLocalKey ,
2632+ ToRemoteKey : keyRing .ToRemoteKey ,
2633+ RevocationKey : TweakPubKeyWithIndex (
2634+ keyRing .RevocationKey , index ,
2635+ ),
2636+ }
2637+ }
0 commit comments