@@ -1263,7 +1263,7 @@ func createSecondLevelHtlcAllocations(chanType channeldb.ChannelType,
12631263 initiator bool , htlcOutputs []* cmsg.AssetOutput , htlcAmt btcutil.Amount ,
12641264 commitCsvDelay uint32 , keys lnwallet.CommitmentKeyRing ,
12651265 outputIndex fn.Option [uint32 ], htlcTimeout fn.Option [uint32 ],
1266- ) ([]* Allocation , error ) {
1266+ htlcIndex uint64 ) ([]* Allocation , error ) {
12671267
12681268 // TODO(roasbeef): thaw height not implemented for taproot chans rn
12691269 // (lease expiry)
@@ -1284,6 +1284,13 @@ func createSecondLevelHtlcAllocations(chanType channeldb.ChannelType,
12841284 "script sibling: %w" , err )
12851285 }
12861286
1287+ // To ensure uniqueness of the script key across HTLCs with the same
1288+ // payment hash and timeout (which would be equal otherwise), we tweak
1289+ // the asset level internal key of the second-level script key as well
1290+ // with the HTLC index. We'll ONLY use this for the asset level, NOT for
1291+ // the BTC level.
1292+ tweakedTree := TweakHtlcTree (htlcTree , htlcIndex )
1293+
12871294 allocations := []* Allocation {{
12881295 Type : SecondLevelHtlcAllocation ,
12891296 // If we're making the second-level transaction just to sign,
@@ -1299,12 +1306,14 @@ func createSecondLevelHtlcAllocations(chanType channeldb.ChannelType,
12991306 ),
13001307 InternalKey : htlcTree .InternalKey ,
13011308 NonAssetLeaves : sibling ,
1302- ScriptKey : asset .NewScriptKey (htlcTree .TaprootKey ),
1309+ ScriptKey : asset .NewScriptKey (tweakedTree .TaprootKey ),
13031310 SortTaprootKeyBytes : schnorr .SerializePubKey (
1311+ // This _must_ remain the non-tweaked key, since this is
1312+ // used for sorting _before_ applying any TAP tweaks.
13041313 htlcTree .TaprootKey ,
13051314 ),
1306- // TODO(roasbeef): don't need it here?
1307- CLTV : htlcTimeout . UnwrapOr ( 0 ) ,
1315+ CLTV : htlcTimeout . UnwrapOr ( 0 ),
1316+ HtlcIndex : htlcIndex ,
13081317 }}
13091318
13101319 return allocations , nil
@@ -1316,12 +1325,12 @@ func CreateSecondLevelHtlcPackets(chanState lnwallet.AuxChanState,
13161325 commitTx * wire.MsgTx , htlcAmt btcutil.Amount ,
13171326 keys lnwallet.CommitmentKeyRing , chainParams * address.ChainParams ,
13181327 htlcOutputs []* cmsg.AssetOutput , htlcTimeout fn.Option [uint32 ],
1319- ) ([]* tappsbt.VPacket , []* Allocation , error ) {
1328+ htlcIndex uint64 ) ([]* tappsbt.VPacket , []* Allocation , error ) {
13201329
13211330 allocations , err := createSecondLevelHtlcAllocations (
13221331 chanState .ChanType , chanState .IsInitiator ,
13231332 htlcOutputs , htlcAmt , uint32 (chanState .LocalChanCfg .CsvDelay ),
1324- keys , fn .None [uint32 ](), htlcTimeout ,
1333+ keys , fn .None [uint32 ](), htlcTimeout , htlcIndex ,
13251334 )
13261335 if err != nil {
13271336 return nil , nil , err
@@ -1367,13 +1376,13 @@ func CreateSecondLevelHtlcTx(chanState lnwallet.AuxChanState,
13671376 commitTx * wire.MsgTx , htlcAmt btcutil.Amount ,
13681377 keys lnwallet.CommitmentKeyRing , chainParams * address.ChainParams ,
13691378 htlcOutputs []* cmsg.AssetOutput , htlcTimeout fn.Option [uint32 ],
1370- ) (input.AuxTapLeaf , error ) {
1379+ htlcIndex uint64 ) (input.AuxTapLeaf , error ) {
13711380
13721381 none := input .NoneTapLeaf ()
13731382
13741383 vPackets , allocations , err := CreateSecondLevelHtlcPackets (
13751384 chanState , commitTx , htlcAmt , keys , chainParams , htlcOutputs ,
1376- htlcTimeout ,
1385+ htlcTimeout , htlcIndex ,
13771386 )
13781387 if err != nil {
13791388 return none , fmt .Errorf ("error creating second level HTLC " +
0 commit comments