Skip to content

Commit dc7e7bd

Browse files
committed
build+tapchannel: AuxTrafficShaper finds matching available quote
When LND queries the PaymentBandwidth there's no way to signal back which RFQ ID ended up being used for that bandwidth calculation. We rely on the assumption that one quote is established per peer within the scope of a payment. This way, the AuxTrafficShaper methods spot the quote that it needs to use by matching the peer of the quote with the peer that LND is going to send this HTLC to.
1 parent 3aeb94b commit dc7e7bd

File tree

4 files changed

+73
-28
lines changed

4 files changed

+73
-28
lines changed

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ require (
128128
github.com/lightninglabs/lightning-node-connect/gbn v1.0.1 // indirect
129129
github.com/lightninglabs/lightning-node-connect/mailbox v1.0.1 // indirect
130130
github.com/lightninglabs/neutrino v0.16.1 // indirect
131-
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb // indirect
131+
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9 // indirect
132132
github.com/lightningnetwork/lnd/healthcheck v1.2.6 // indirect
133133
github.com/lightningnetwork/lnd/kvdb v1.4.16 // indirect
134134
github.com/lightningnetwork/lnd/queue v1.1.1 // indirect
@@ -217,3 +217,7 @@ replace github.com/golang-migrate/migrate/v4 => github.com/lightninglabs/migrate
217217

218218
// Note this is a temproary replace and will be removed when taprpc is tagged.
219219
replace github.com/lightninglabs/taproot-assets/taprpc => ./taprpc
220+
221+
replace github.com/lightningnetwork/lnd => github.com/GeorgeTsagk/lnd v0.0.0-20250626101156-ba3b13f67b65
222+
223+
replace github.com/lightningnetwork/lnd/sqldb => github.com/GeorgeTsagk/lnd/sqldb v0.0.0-20250626101156-ba3b13f67b65

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,10 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
603603
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
604604
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
605605
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
606+
github.com/GeorgeTsagk/lnd v0.0.0-20250626101156-ba3b13f67b65 h1:kUp+TFKIEkNypN7VvlqYdZ1xFHop3Axuv6AII7TWtto=
607+
github.com/GeorgeTsagk/lnd v0.0.0-20250626101156-ba3b13f67b65/go.mod h1:FelbuiQdzwyEbHng3XsODMBKfXUGgz6JZcWtN9uwuE4=
608+
github.com/GeorgeTsagk/lnd/sqldb v0.0.0-20250626101156-ba3b13f67b65 h1:bk+LF8bpnlfqyzTiy2xONBg6aqiGo9HFWgUmidjiRiE=
609+
github.com/GeorgeTsagk/lnd/sqldb v0.0.0-20250626101156-ba3b13f67b65/go.mod h1:c/vWoQfcxu6FAfHzGajkIQi7CEIeIZFhhH4DYh1BJpc=
606610
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
607611
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
608612
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
@@ -1147,10 +1151,8 @@ github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3
11471151
github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo=
11481152
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display h1:w7FM5LH9Z6CpKxl13mS48idsu6F+cEZf0lkyiV+Dq9g=
11491153
github.com/lightninglabs/protobuf-go-hex-display v1.34.2-hex-display/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
1150-
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY=
1151-
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
1152-
github.com/lightningnetwork/lnd v0.19.1-beta.rc1.0.20250623232057-b48e2763a798 h1:nSnOCqilf+ynsJlTOVOoNXEhjjxTrvcv6jxMyUlZJJE=
1153-
github.com/lightningnetwork/lnd v0.19.1-beta.rc1.0.20250623232057-b48e2763a798/go.mod h1:iHZ/FHFK00BqV6qgDkZZfqWE3LGtgE0U5KdO5WrM+eQ=
1154+
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9 h1:6D3LrdagJweLLdFm1JNodZsBk6iU4TTsBBFLQ4yiXfI=
1155+
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240815225420-8b40adf04ab9/go.mod h1:EDqJ3MuZIbMq0QI1czTIKDJ/GS8S14RXPwapHw8cw6w=
11541156
github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf0d0Uy4qBjI=
11551157
github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U=
11561158
github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=
@@ -1163,8 +1165,6 @@ github.com/lightningnetwork/lnd/kvdb v1.4.16 h1:9BZgWdDfjmHRHLS97cz39bVuBAqMc4/p
11631165
github.com/lightningnetwork/lnd/kvdb v1.4.16/go.mod h1:HW+bvwkxNaopkz3oIgBV6NEnV4jCEZCACFUcNg4xSjM=
11641166
github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI=
11651167
github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4=
1166-
github.com/lightningnetwork/lnd/sqldb v1.0.10 h1:ZLV7TGwjnKupVfCd+DJ43MAc9BKVSFCnvhpSPGKdN3M=
1167-
github.com/lightningnetwork/lnd/sqldb v1.0.10/go.mod h1:c/vWoQfcxu6FAfHzGajkIQi7CEIeIZFhhH4DYh1BJpc=
11681168
github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM=
11691169
github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA=
11701170
github.com/lightningnetwork/lnd/tlv v1.3.2 h1:MO4FCk7F4k5xPMqVZF6Nb/kOpxlwPrUQpYjmyKny5s0=

server.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"github.com/lightningnetwork/lnd/lnwire"
4141
"github.com/lightningnetwork/lnd/macaroons"
4242
"github.com/lightningnetwork/lnd/msgmux"
43+
"github.com/lightningnetwork/lnd/routing/route"
4344
"github.com/lightningnetwork/lnd/sweep"
4445
"github.com/lightningnetwork/lnd/tlv"
4546
"google.golang.org/grpc"
@@ -1045,8 +1046,8 @@ func (s *Server) ShouldHandleTraffic(cid lnwire.ShortChannelID,
10451046
// NOTE: This method is part of the routing.TlvTrafficShaper interface.
10461047
func (s *Server) PaymentBandwidth(fundingBlob, htlcBlob,
10471048
commitmentBlob lfn.Option[tlv.Blob], linkBandwidth,
1048-
htlcAmt lnwire.MilliSatoshi,
1049-
htlcView lnwallet.AuxHtlcView) (lnwire.MilliSatoshi, error) {
1049+
htlcAmt lnwire.MilliSatoshi, htlcView lnwallet.AuxHtlcView,
1050+
peer *route.Vertex) (lnwire.MilliSatoshi, error) {
10501051

10511052
srvrLog.Debugf("PaymentBandwidth called, fundingBlob=%v, htlcBlob=%v, "+
10521053
"commitmentBlob=%v", lnutils.SpewLogClosure(fundingBlob),
@@ -1059,7 +1060,7 @@ func (s *Server) PaymentBandwidth(fundingBlob, htlcBlob,
10591060

10601061
return s.cfg.AuxTrafficShaper.PaymentBandwidth(
10611062
fundingBlob, htlcBlob, commitmentBlob, linkBandwidth, htlcAmt,
1062-
htlcView,
1063+
htlcView, peer,
10631064
)
10641065
}
10651066

@@ -1069,8 +1070,8 @@ func (s *Server) PaymentBandwidth(fundingBlob, htlcBlob,
10691070
//
10701071
// NOTE: This method is part of the routing.TlvTrafficShaper interface.
10711072
func (s *Server) ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi,
1072-
htlcCustomRecords lnwire.CustomRecords) (lnwire.MilliSatoshi,
1073-
lnwire.CustomRecords, error) {
1073+
htlcCustomRecords lnwire.CustomRecords,
1074+
peer *route.Vertex) (lnwire.MilliSatoshi, lnwire.CustomRecords, error) {
10741075

10751076
srvrLog.Debugf("ProduceHtlcExtraData called, totalAmount=%d, "+
10761077
"htlcBlob=%v", totalAmount,
@@ -1081,7 +1082,7 @@ func (s *Server) ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi,
10811082
}
10821083

10831084
return s.cfg.AuxTrafficShaper.ProduceHtlcExtraData(
1084-
totalAmount, htlcCustomRecords,
1085+
totalAmount, htlcCustomRecords, peer,
10851086
)
10861087
}
10871088

tapchannel/aux_traffic_shaper.go

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tapchannel
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"sync"
@@ -19,6 +20,7 @@ import (
1920
"github.com/lightningnetwork/lnd/lnutils"
2021
"github.com/lightningnetwork/lnd/lnwallet"
2122
"github.com/lightningnetwork/lnd/lnwire"
23+
"github.com/lightningnetwork/lnd/routing/route"
2224
"github.com/lightningnetwork/lnd/tlv"
2325
)
2426

@@ -116,8 +118,8 @@ func (s *AuxTrafficShaper) ShouldHandleTraffic(cid lnwire.ShortChannelID,
116118
// called first.
117119
func (s *AuxTrafficShaper) PaymentBandwidth(fundingBlob, htlcBlob,
118120
commitmentBlob lfn.Option[tlv.Blob], linkBandwidth,
119-
htlcAmt lnwire.MilliSatoshi,
120-
htlcView lnwallet.AuxHtlcView) (lnwire.MilliSatoshi, error) {
121+
htlcAmt lnwire.MilliSatoshi, htlcView lnwallet.AuxHtlcView,
122+
peer *route.Vertex) (lnwire.MilliSatoshi, error) {
121123

122124
fundingBlobBytes := fundingBlob.UnwrapOr(nil)
123125
htlcBytes := htlcBlob.UnwrapOr(nil)
@@ -230,6 +232,7 @@ func (s *AuxTrafficShaper) PaymentBandwidth(fundingBlob, htlcBlob,
230232
// the asset units in our local balance.
231233
return s.paymentBandwidth(
232234
htlc, computedLocal, linkBandwidth, minHtlcAmt, fundingChan,
235+
peer,
233236
)
234237
}
235238

@@ -277,11 +280,12 @@ func paymentBandwidthAssetUnits(htlcAssetAmount, computedLocal uint64,
277280
}
278281

279282
// paymentBandwidth returns the available payment bandwidth of the channel based
280-
// on the list of availalbe RFQ IDs. If any of those IDs matches the channel, we
283+
// on the list of available RFQ IDs. If any of those IDs matches the channel, we
281284
// calculate the bandwidth based on its asset rate.
282285
func (s *AuxTrafficShaper) paymentBandwidth(htlc *rfqmsg.Htlc,
283286
localBalance uint64, linkBandwidth, minHtlcAmt lnwire.MilliSatoshi,
284-
fundingChan *cmsg.OpenChannel) (lnwire.MilliSatoshi, error) {
287+
fundingChan *cmsg.OpenChannel,
288+
peer *route.Vertex) (lnwire.MilliSatoshi, error) {
285289

286290
// If the HTLC doesn't have any available RFQ IDs, it's incomplete, and
287291
// we cannot determine the bandwidth.
@@ -292,26 +296,29 @@ func (s *AuxTrafficShaper) paymentBandwidth(htlc *rfqmsg.Htlc,
292296
}
293297

294298
// Retrieve the available RFQ IDs.
295-
avaliableIDs := htlc.AvailableRfqIDs.UnsafeFromSome().Val.IDs
299+
availableIDs := htlc.AvailableRfqIDs.UnsafeFromSome().Val.IDs
296300

297301
// For this rfqID we'll fetch the corresponding quote and rate.
298302
acceptedSellQuotes := s.cfg.RfqManager.PeerAcceptedSellQuotes()
299303
acceptedBuyQuotes := s.cfg.RfqManager.LocalAcceptedBuyQuotes()
300304

301-
for _, rfqID := range avaliableIDs {
305+
for _, rfqID := range availableIDs {
302306
sellQuote, isSellQuote := acceptedSellQuotes[rfqID.Scid()]
303307
buyQuote, isBuyQuote := acceptedBuyQuotes[rfqID.Scid()]
304308

305309
var (
306310
rate rfqmsg.AssetRate
307311
specifier asset.Specifier
312+
quotePeer *route.Vertex
308313
)
309314
switch {
310315
case isSellQuote:
316+
quotePeer = &sellQuote.Peer
311317
rate = sellQuote.AssetRate
312318
specifier = sellQuote.Request.AssetSpecifier
313319

314320
case isBuyQuote:
321+
quotePeer = &buyQuote.Peer
315322
rate = buyQuote.AssetRate
316323
specifier = buyQuote.Request.AssetSpecifier
317324

@@ -320,6 +327,12 @@ func (s *AuxTrafficShaper) paymentBandwidth(htlc *rfqmsg.Htlc,
320327
"ID %x (SCID %d)", rfqID[:], rfqID.Scid())
321328
}
322329

330+
// If the channel peer does not match the quote peer, continue
331+
// to the next available quote.
332+
if !bytes.Equal(quotePeer[:], peer[:]) {
333+
continue
334+
}
335+
323336
bandwidth, err := s.paymentBandwidthRFQ(
324337
rfqID, rate, specifier, localBalance, linkBandwidth,
325338
minHtlcAmt, fundingChan,
@@ -431,8 +444,8 @@ func ComputeLocalBalance(commitment cmsg.Commitment,
431444
// blob of an HTLC, may produce a different blob or modify the amount of bitcoin
432445
// this HTLC should carry.
433446
func (s *AuxTrafficShaper) ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi,
434-
htlcCustomRecords lnwire.CustomRecords) (lnwire.MilliSatoshi,
435-
lnwire.CustomRecords, error) {
447+
htlcCustomRecords lnwire.CustomRecords,
448+
peer *route.Vertex) (lnwire.MilliSatoshi, lnwire.CustomRecords, error) {
436449

437450
if !rfqmsg.HasAssetHTLCCustomRecords(htlcCustomRecords) {
438451
log.Tracef("No asset HTLC custom records, not producing " +
@@ -456,16 +469,43 @@ func (s *AuxTrafficShaper) ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi,
456469
return totalAmount, htlcCustomRecords, nil
457470
}
458471

459-
if htlc.RfqID.ValOpt().IsNone() {
460-
return 0, nil, fmt.Errorf("no RFQ ID present in HTLC blob")
472+
if htlc.AvailableRfqIDs.IsNone() {
473+
return 0, nil, fmt.Errorf("no available RFQ IDs present in " +
474+
"HTLC blob")
461475
}
462476

463-
rfqID := htlc.RfqID.ValOpt().UnsafeFromSome()
464477
acceptedQuotes := s.cfg.RfqManager.PeerAcceptedSellQuotes()
465-
quote, ok := acceptedQuotes[rfqID.Scid()]
466-
if !ok {
467-
return 0, nil, fmt.Errorf("no accepted quote found for RFQ ID "+
468-
"%x (SCID %d)", rfqID[:], rfqID.Scid())
478+
availableIDs := htlc.AvailableRfqIDs.UnsafeFromSome().Val.IDs
479+
480+
var (
481+
rfqID rfqmsg.ID
482+
quote rfqmsg.SellAccept
483+
)
484+
485+
// Let's find the quote that matches this peer. This will be the quote
486+
// that we'll use to calculate the asset units. Given that we may only
487+
// establish a maximum of 1 quote per peer per payment, this check is
488+
// safe to perform as there are no competing quotes for a certain peer.
489+
for _, id := range availableIDs {
490+
q, ok := acceptedQuotes[id.Scid()]
491+
if !ok {
492+
continue
493+
}
494+
495+
// We found the quote to use, now let's set the related fields.
496+
if q.Peer.String() == peer.String() {
497+
// This is the actual RFQ ID that our peer will use to
498+
// perform checks on their end.
499+
rfqID = id
500+
htlc.RfqID = rfqmsg.SomeRfqIDRecord(rfqID)
501+
quote = q
502+
break
503+
}
504+
}
505+
506+
if htlc.RfqID.IsNone() {
507+
return 0, nil, fmt.Errorf("none of the available RFQ IDs "+
508+
"match our peer=%s", peer)
469509
}
470510

471511
// Now that we've queried the accepted quote, we know how many asset

0 commit comments

Comments
 (0)