Skip to content

Commit 94c5c9a

Browse files
committed
tapchannel+tapchannelmsg: check quote vs. channel compat
During pathfinding, when an HTLC doesn't have an asset ID or group key encoded, we can only find out if a channel is compatible after looking at the specifier of the quote. We add that to make sure pathfinding doesn't give false positives for channels that then can't be used because they're not compatible.
1 parent b68ee1f commit 94c5c9a

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

tapchannel/aux_traffic_shaper.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ func (s *AuxTrafficShaper) PaymentBandwidth(fundingBlob, htlcBlob,
228228
// Otherwise, we derive the available bandwidth from the HTLC's RFQ and
229229
// the asset units in our local balance.
230230
return s.paymentBandwidth(
231-
htlc, computedLocal, linkBandwidth, minHtlcAmt,
231+
htlc, computedLocal, linkBandwidth, minHtlcAmt, fundingChan,
232232
)
233233
}
234234

@@ -279,8 +279,8 @@ func paymentBandwidthAssetUnits(htlcAssetAmount, computedLocal uint64,
279279
// on the asset rate of the RFQ quote that is included in the HTLC and the asset
280280
// units of the local balance.
281281
func (s *AuxTrafficShaper) paymentBandwidth(htlc *rfqmsg.Htlc,
282-
localBalance uint64, linkBandwidth,
283-
minHtlcAmt lnwire.MilliSatoshi) (lnwire.MilliSatoshi, error) {
282+
localBalance uint64, linkBandwidth, minHtlcAmt lnwire.MilliSatoshi,
283+
fundingChan *cmsg.OpenChannel) (lnwire.MilliSatoshi, error) {
284284

285285
// If the HTLC doesn't have an RFQ ID, it's incomplete, and we cannot
286286
// determine the bandwidth.
@@ -301,19 +301,34 @@ func (s *AuxTrafficShaper) paymentBandwidth(htlc *rfqmsg.Htlc,
301301
sellQuote, isSellQuote := acceptedSellQuotes[rfqID.Scid()]
302302
buyQuote, isBuyQuote := acceptedBuyQuotes[rfqID.Scid()]
303303

304-
var rate rfqmsg.AssetRate
304+
var (
305+
rate rfqmsg.AssetRate
306+
specifier asset.Specifier
307+
)
305308
switch {
306309
case isSellQuote:
307310
rate = sellQuote.AssetRate
311+
specifier = sellQuote.Request.AssetSpecifier
308312

309313
case isBuyQuote:
310314
rate = buyQuote.AssetRate
315+
specifier = buyQuote.Request.AssetSpecifier
311316

312317
default:
313318
return 0, fmt.Errorf("no accepted quote found for RFQ ID "+
314319
"%x (SCID %d)", rfqID[:], rfqID.Scid())
315320
}
316321

322+
// Now that we found the quote, we can determine if this quote is even
323+
// compatible with this channel. If not, we cannot forward the HTLC
324+
// and should return 0 bandwidth.
325+
if !fundingChan.Compatible(specifier) {
326+
log.Tracef("Quote with ID %x (SCID %d) not compatible with "+
327+
"channel assets, returning 0 bandwidth", rfqID[:],
328+
rfqID.Scid())
329+
return 0, nil
330+
}
331+
317332
// Calculate the local available balance in the local asset unit,
318333
// expressed in milli-satoshis.
319334
localBalanceFp := rfqmath.NewBigIntFixedPoint(localBalance, 0)

tapchannelmsg/records.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,34 @@ func (o *OpenChannel) HasAllAssetIDs(ids fn.Set[asset.ID]) bool {
229229
return ids.Subset(availableIDs)
230230
}
231231

232+
// Compatible checks if the OpenChannel is compatible with the given asset
233+
// specifier.
234+
func (o *OpenChannel) Compatible(specifier asset.Specifier) bool {
235+
switch {
236+
case specifier.HasGroupPubKey():
237+
targetGroupKey := specifier.UnwrapGroupKeyToPtr()
238+
if targetGroupKey == nil {
239+
return false
240+
}
241+
242+
// If the specifier has a group key, then we must have a group
243+
// key set on the OpenChannel.
244+
return lfn.MapOptionZ(
245+
o.GroupKey.ValOpt(),
246+
func(groupKey *btcec.PublicKey) bool {
247+
return targetGroupKey.IsEqual(groupKey)
248+
},
249+
)
250+
251+
default:
252+
// If the specifier has an asset ID, we check if that ID is
253+
// contained within the OpenChannel's assets.
254+
return fn.MapOptionZ(specifier.ID(), func(id asset.ID) bool {
255+
return o.HasAllAssetIDs(fn.NewSet(id))
256+
})
257+
}
258+
}
259+
232260
// DecodeOpenChannel deserializes an OpenChannel from the given blob.
233261
func DecodeOpenChannel(blob tlv.Blob) (*OpenChannel, error) {
234262
var o OpenChannel

0 commit comments

Comments
 (0)