@@ -551,6 +551,13 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
551
551
remoteOutputIndex = htlc .OutputIndex
552
552
}
553
553
554
+ customRecords := htlc .CustomRecords .Copy ()
555
+ entryType := Add
556
+
557
+ if shouldSetNoop (customRecords , lc .channelState .ChanType ) {
558
+ entryType = NoopAdd
559
+ }
560
+
554
561
// With the scripts reconstructed (depending on if this is our commit
555
562
// vs theirs or a pending commit for the remote party), we can now
556
563
// re-create the original payment descriptor.
@@ -559,7 +566,7 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
559
566
RHash : htlc .RHash ,
560
567
Timeout : htlc .RefundTimeout ,
561
568
Amount : htlc .Amt ,
562
- EntryType : Add ,
569
+ EntryType : entryType ,
563
570
HtlcIndex : htlc .HtlcIndex ,
564
571
LogIndex : htlc .LogIndex ,
565
572
OnionBlob : htlc .OnionBlob ,
@@ -570,7 +577,7 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
570
577
theirPkScript : theirP2WSH ,
571
578
theirWitnessScript : theirWitnessScript ,
572
579
BlindingPoint : htlc .BlindingPoint ,
573
- CustomRecords : htlc . CustomRecords . Copy () ,
580
+ CustomRecords : customRecords ,
574
581
}, nil
575
582
}
576
583
@@ -1100,6 +1107,10 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
1100
1107
},
1101
1108
}
1102
1109
1110
+ if shouldSetNoop (pd .CustomRecords , lc .channelState .ChanType ) {
1111
+ pd .EntryType = NoopAdd
1112
+ }
1113
+
1103
1114
isDustRemote := HtlcIsDust (
1104
1115
lc .channelState .ChanType , false , lntypes .Remote ,
1105
1116
feeRate , wireMsg .Amount .ToSatoshis (), remoteDustLimit ,
@@ -1336,6 +1347,10 @@ func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpd
1336
1347
},
1337
1348
}
1338
1349
1350
+ if shouldSetNoop (pd .CustomRecords , lc .channelState .ChanType ) {
1351
+ pd .EntryType = NoopAdd
1352
+ }
1353
+
1339
1354
// We don't need to generate an htlc script yet. This will be
1340
1355
// done once we sign our remote commitment.
1341
1356
@@ -1736,7 +1751,7 @@ func (lc *LightningChannel) restorePendingRemoteUpdates(
1736
1751
// but this Add restoration was a no-op as every single one of
1737
1752
// these Adds was already restored since they're all incoming
1738
1753
// htlcs on the local commitment.
1739
- if payDesc .EntryType == Add {
1754
+ if payDesc .isAdd () {
1740
1755
continue
1741
1756
}
1742
1757
@@ -1881,7 +1896,7 @@ func (lc *LightningChannel) restorePendingLocalUpdates(
1881
1896
}
1882
1897
1883
1898
switch payDesc .EntryType {
1884
- case Add :
1899
+ case Add , NoopAdd :
1885
1900
// The HtlcIndex of the added HTLC _must_ be equal to
1886
1901
// the log's htlcCounter at this point. If it is not we
1887
1902
// panic to catch this.
@@ -2993,6 +3008,50 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView,
2993
3008
)
2994
3009
if rmvHeight == 0 {
2995
3010
switch {
3011
+ // If this a noop add, then when we settle the
3012
+ // HTLC, we actually credit the sender with the
3013
+ // amount again, thus making it a noop. Noop
3014
+ // HTLCs are only triggered by external software
3015
+ // using the AuxComponents and only for channels
3016
+ // that use the custom tapscript root.
3017
+ case entry .EntryType == Settle &&
3018
+ addEntry .EntryType == NoopAdd :
3019
+
3020
+ channel := lc .channelState
3021
+ party := party
3022
+
3023
+ delta := btcutil .Amount (
3024
+ balanceDeltas .GetForParty (
3025
+ party ,
3026
+ ),
3027
+ )
3028
+
3029
+ // If the receiver has existing balance
3030
+ // above dust then we go ahead with
3031
+ // crediting the amount back to the
3032
+ // sender. Otherwise we give the amount
3033
+ // to the receiver. We do this because
3034
+ // the receiver needs some above-dust
3035
+ // balance to anchor the AuxBlob. We
3036
+ // also pass in the so-far calculated
3037
+ // delta for the party, as that's
3038
+ // effectively part of their balance
3039
+ // within this view computation.
3040
+ if channel .BalanceAboveReserve (
3041
+ party , delta ,
3042
+ ) {
3043
+
3044
+ party = party .CounterParty ()
3045
+ }
3046
+
3047
+ d := int64 (entry .Amount )
3048
+ balanceDeltas .ModifyForParty (
3049
+ party ,
3050
+ func (acc int64 ) int64 {
3051
+ return acc + d
3052
+ },
3053
+ )
3054
+
2996
3055
// If an incoming HTLC is being settled, then
2997
3056
// this means that the preimage has been
2998
3057
// received by the settling party Therefore, we
@@ -3030,7 +3089,7 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView,
3030
3089
liveAdds := fn .Filter (
3031
3090
view .Updates .GetForParty (party ),
3032
3091
func (pd * paymentDescriptor ) bool {
3033
- isAdd := pd .EntryType == Add
3092
+ isAdd := pd .isAdd ()
3034
3093
shouldSkip := skip .GetForParty (party ).
3035
3094
Contains (pd .HtlcIndex )
3036
3095
@@ -3069,7 +3128,7 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView,
3069
3128
// corresponding to whoseCommitmentChain.
3070
3129
isUncommitted := func (update * paymentDescriptor ) bool {
3071
3130
switch update .EntryType {
3072
- case Add :
3131
+ case Add , NoopAdd :
3073
3132
return update .addCommitHeights .GetForParty (
3074
3133
whoseCommitChain ,
3075
3134
) == 0
@@ -3833,7 +3892,7 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter,
3833
3892
// Go through all updates, checking that they don't violate the
3834
3893
// channel constraints.
3835
3894
for _ , entry := range updates {
3836
- if entry .EntryType == Add {
3895
+ if entry .isAdd () {
3837
3896
// An HTLC is being added, this will add to the
3838
3897
// number and amount in flight.
3839
3898
amtInFlight += entry .Amount
@@ -5712,7 +5771,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
5712
5771
// don't re-forward any already processed HTLC's after a
5713
5772
// restart.
5714
5773
switch {
5715
- case pd .EntryType == Add && committedAdd && shouldFwdAdd :
5774
+ case pd .isAdd () && committedAdd && shouldFwdAdd :
5716
5775
// Construct a reference specifying the location that
5717
5776
// this forwarded Add will be written in the forwarding
5718
5777
// package constructed at this remote height.
@@ -5731,7 +5790,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
5731
5790
addUpdatesToForward , pd .toLogUpdate (),
5732
5791
)
5733
5792
5734
- case pd .EntryType != Add && committedRmv && shouldFwdRmv :
5793
+ case ! pd .isAdd () && committedRmv && shouldFwdRmv :
5735
5794
// Construct a reference specifying the location that
5736
5795
// this forwarded Settle/Fail will be written in the
5737
5796
// forwarding package constructed at this remote height.
@@ -5970,7 +6029,7 @@ func (lc *LightningChannel) GetDustSum(whoseCommit lntypes.ChannelParty,
5970
6029
// Grab all of our HTLCs and evaluate against the dust limit.
5971
6030
for e := lc .updateLogs .Local .Front (); e != nil ; e = e .Next () {
5972
6031
pd := e .Value
5973
- if pd .EntryType != Add {
6032
+ if ! pd .isAdd () {
5974
6033
continue
5975
6034
}
5976
6035
@@ -5989,7 +6048,7 @@ func (lc *LightningChannel) GetDustSum(whoseCommit lntypes.ChannelParty,
5989
6048
// Grab all of their HTLCs and evaluate against the dust limit.
5990
6049
for e := lc .updateLogs .Remote .Front (); e != nil ; e = e .Next () {
5991
6050
pd := e .Value
5992
- if pd .EntryType != Add {
6051
+ if ! pd .isAdd () {
5993
6052
continue
5994
6053
}
5995
6054
@@ -6062,9 +6121,15 @@ func (lc *LightningChannel) MayAddOutgoingHtlc(amt lnwire.MilliSatoshi) error {
6062
6121
func (lc * LightningChannel ) htlcAddDescriptor (htlc * lnwire.UpdateAddHTLC ,
6063
6122
openKey * models.CircuitKey ) * paymentDescriptor {
6064
6123
6124
+ entryType := Add
6125
+ customRecords := htlc .CustomRecords .Copy ()
6126
+ if shouldSetNoop (customRecords , lc .channelState .ChanType ) {
6127
+ entryType = NoopAdd
6128
+ }
6129
+
6065
6130
return & paymentDescriptor {
6066
6131
ChanID : htlc .ChanID ,
6067
- EntryType : Add ,
6132
+ EntryType : entryType ,
6068
6133
RHash : PaymentHash (htlc .PaymentHash ),
6069
6134
Timeout : htlc .Expiry ,
6070
6135
Amount : htlc .Amount ,
@@ -6073,7 +6138,7 @@ func (lc *LightningChannel) htlcAddDescriptor(htlc *lnwire.UpdateAddHTLC,
6073
6138
OnionBlob : htlc .OnionBlob ,
6074
6139
OpenCircuitKey : openKey ,
6075
6140
BlindingPoint : htlc .BlindingPoint ,
6076
- CustomRecords : htlc . CustomRecords . Copy () ,
6141
+ CustomRecords : customRecords ,
6077
6142
}
6078
6143
}
6079
6144
@@ -6126,17 +6191,23 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64,
6126
6191
lc .updateLogs .Remote .htlcCounter )
6127
6192
}
6128
6193
6194
+ entryType := Add
6195
+ customRecords := htlc .CustomRecords .Copy ()
6196
+ if shouldSetNoop (customRecords , lc .channelState .ChanType ) {
6197
+ entryType = NoopAdd
6198
+ }
6199
+
6129
6200
pd := & paymentDescriptor {
6130
6201
ChanID : htlc .ChanID ,
6131
- EntryType : Add ,
6202
+ EntryType : entryType ,
6132
6203
RHash : PaymentHash (htlc .PaymentHash ),
6133
6204
Timeout : htlc .Expiry ,
6134
6205
Amount : htlc .Amount ,
6135
6206
LogIndex : lc .updateLogs .Remote .logIndex ,
6136
6207
HtlcIndex : lc .updateLogs .Remote .htlcCounter ,
6137
6208
OnionBlob : htlc .OnionBlob ,
6138
6209
BlindingPoint : htlc .BlindingPoint ,
6139
- CustomRecords : htlc . CustomRecords . Copy () ,
6210
+ CustomRecords : customRecords ,
6140
6211
}
6141
6212
6142
6213
localACKedIndex := lc .commitChains .Remote .tail ().messageIndices .Local
@@ -9825,7 +9896,7 @@ func (lc *LightningChannel) unsignedLocalUpdates(remoteMessageIndex,
9825
9896
9826
9897
// We don't save add updates as they are restored from the
9827
9898
// remote commitment in restoreStateLogs.
9828
- if pd .EntryType == Add {
9899
+ if pd .isAdd () {
9829
9900
continue
9830
9901
}
9831
9902
@@ -9999,3 +10070,18 @@ func (lc *LightningChannel) ZeroConfRealScid() fn.Option[lnwire.ShortChannelID]
9999
10070
10000
10071
return fn .None [lnwire.ShortChannelID ]()
10001
10072
}
10073
+
10074
+ // shouldSetNoop checks the custom records of the entry and the channel type and
10075
+ // returns a boolean indicating whether this add entry should be converted to a
10076
+ // noop add type. This will only return true if the TLV field signalling the use
10077
+ // of a noop HTLC is set, and the channel has a custom tapscript root.
10078
+ func shouldSetNoop (records lnwire.CustomRecords ,
10079
+ chanType channeldb.ChannelType ) bool {
10080
+
10081
+ noopTLV := uint64 (NoopHtlcType .TypeVal ())
10082
+ if _ , ok := records [noopTLV ]; ok && chanType .HasTapscriptRoot () {
10083
+ return true
10084
+ }
10085
+
10086
+ return false
10087
+ }
0 commit comments