11package tapchannel
22
33import (
4+ "context"
45 "fmt"
56 "sync"
67
@@ -228,7 +229,7 @@ func (s *AuxTrafficShaper) PaymentBandwidth(fundingBlob, htlcBlob,
228229 // Otherwise, we derive the available bandwidth from the HTLC's RFQ and
229230 // the asset units in our local balance.
230231 return s .paymentBandwidth (
231- htlc , computedLocal , linkBandwidth , minHtlcAmt ,
232+ htlc , computedLocal , linkBandwidth , minHtlcAmt , fundingChan ,
232233 )
233234}
234235
@@ -279,8 +280,8 @@ func paymentBandwidthAssetUnits(htlcAssetAmount, computedLocal uint64,
279280// on the asset rate of the RFQ quote that is included in the HTLC and the asset
280281// units of the local balance.
281282func (s * AuxTrafficShaper ) paymentBandwidth (htlc * rfqmsg.Htlc ,
282- localBalance uint64 , linkBandwidth ,
283- minHtlcAmt lnwire. MilliSatoshi ) (lnwire.MilliSatoshi , error ) {
283+ localBalance uint64 , linkBandwidth , minHtlcAmt lnwire. MilliSatoshi ,
284+ fundingChan * cmsg. OpenChannel ) (lnwire.MilliSatoshi , error ) {
284285
285286 // If the HTLC doesn't have an RFQ ID, it's incomplete, and we cannot
286287 // determine the bandwidth.
@@ -301,19 +302,54 @@ func (s *AuxTrafficShaper) paymentBandwidth(htlc *rfqmsg.Htlc,
301302 sellQuote , isSellQuote := acceptedSellQuotes [rfqID .Scid ()]
302303 buyQuote , isBuyQuote := acceptedBuyQuotes [rfqID .Scid ()]
303304
304- var rate rfqmsg.AssetRate
305+ var (
306+ rate rfqmsg.AssetRate
307+ specifier asset.Specifier
308+ )
305309 switch {
306310 case isSellQuote :
307311 rate = sellQuote .AssetRate
312+ specifier = sellQuote .Request .AssetSpecifier
308313
309314 case isBuyQuote :
310315 rate = buyQuote .AssetRate
316+ specifier = buyQuote .Request .AssetSpecifier
311317
312318 default :
313319 return 0 , fmt .Errorf ("no accepted quote found for RFQ ID " +
314320 "%x (SCID %d)" , rfqID [:], rfqID .Scid ())
315321 }
316322
323+ // Now that we found the quote, we can determine if this quote is even
324+ // compatible with this channel. If not, we cannot forward the HTLC
325+ // and should return 0 bandwidth.
326+ for _ , b := range fundingChan .FundedAssets .Val .Outputs {
327+ // We define compatibility by making sure that each asset in the
328+ // channel matches the specifier of the RFQ quote. This means
329+ // if the quote was created for a single asset in a grouped
330+ // asset channel with multiple tranches, then the check will
331+ // return false, because the group key needs to be used in that
332+ // case. But this matches the behavior in other areas, where we
333+ // also use AssetMatchesSpecifier.
334+ match , err := s .cfg .RfqManager .AssetMatchesSpecifier (
335+ context .Background (), specifier , b .AssetID .Val ,
336+ )
337+ if err != nil {
338+ return 0 , fmt .Errorf ("error checking if asset ID %x " +
339+ "matches specifier %s: %w" , b .AssetID .Val [:],
340+ specifier .String (), err )
341+ }
342+
343+ // One of the asset IDs in the channel does not match the quote,
344+ // we don't want to route this HTLC over this channel.
345+ if ! match {
346+ log .Tracef ("Quote with ID %x (SCID %d) not compatible " +
347+ "with channel assets, returning 0 bandwidth" ,
348+ rfqID [:], rfqID .Scid ())
349+ return 0 , nil
350+ }
351+ }
352+
317353 // Calculate the local available balance in the local asset unit,
318354 // expressed in milli-satoshis.
319355 localBalanceFp := rfqmath .NewBigIntFixedPoint (localBalance , 0 )
0 commit comments