1
1
package tapchannel
2
2
3
3
import (
4
+ "context"
4
5
"fmt"
5
6
"sync"
6
7
@@ -228,7 +229,7 @@ func (s *AuxTrafficShaper) PaymentBandwidth(fundingBlob, htlcBlob,
228
229
// Otherwise, we derive the available bandwidth from the HTLC's RFQ and
229
230
// the asset units in our local balance.
230
231
return s .paymentBandwidth (
231
- htlc , computedLocal , linkBandwidth , minHtlcAmt ,
232
+ htlc , computedLocal , linkBandwidth , minHtlcAmt , fundingChan ,
232
233
)
233
234
}
234
235
@@ -279,8 +280,8 @@ func paymentBandwidthAssetUnits(htlcAssetAmount, computedLocal uint64,
279
280
// on the asset rate of the RFQ quote that is included in the HTLC and the asset
280
281
// units of the local balance.
281
282
func (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 ) {
284
285
285
286
// If the HTLC doesn't have an RFQ ID, it's incomplete, and we cannot
286
287
// determine the bandwidth.
@@ -301,19 +302,54 @@ func (s *AuxTrafficShaper) paymentBandwidth(htlc *rfqmsg.Htlc,
301
302
sellQuote , isSellQuote := acceptedSellQuotes [rfqID .Scid ()]
302
303
buyQuote , isBuyQuote := acceptedBuyQuotes [rfqID .Scid ()]
303
304
304
- var rate rfqmsg.AssetRate
305
+ var (
306
+ rate rfqmsg.AssetRate
307
+ specifier asset.Specifier
308
+ )
305
309
switch {
306
310
case isSellQuote :
307
311
rate = sellQuote .AssetRate
312
+ specifier = sellQuote .Request .AssetSpecifier
308
313
309
314
case isBuyQuote :
310
315
rate = buyQuote .AssetRate
316
+ specifier = buyQuote .Request .AssetSpecifier
311
317
312
318
default :
313
319
return 0 , fmt .Errorf ("no accepted quote found for RFQ ID " +
314
320
"%x (SCID %d)" , rfqID [:], rfqID .Scid ())
315
321
}
316
322
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
+
317
353
// Calculate the local available balance in the local asset unit,
318
354
// expressed in milli-satoshis.
319
355
localBalanceFp := rfqmath .NewBigIntFixedPoint (localBalance , 0 )
0 commit comments