11package routing
22
33import (
4+ "fmt"
5+
6+ "github.com/btcsuite/btcd/btcutil"
47 "github.com/lightningnetwork/lnd/channeldb"
8+ "github.com/lightningnetwork/lnd/fn"
59 "github.com/lightningnetwork/lnd/htlcswitch"
610 "github.com/lightningnetwork/lnd/lnwire"
711 "github.com/lightningnetwork/lnd/routing/route"
12+ "github.com/lightningnetwork/lnd/tlv"
813)
914
1015// bandwidthHints provides hints about the currently available balance in our
@@ -18,7 +23,39 @@ type bandwidthHints interface {
1823 // will be used. If the channel is unavailable, a zero amount is
1924 // returned.
2025 availableChanBandwidth (channelID uint64 ,
21- amount lnwire.MilliSatoshi ) (lnwire.MilliSatoshi , bool )
26+ amount lnwire.MilliSatoshi ,
27+ htlcBlob fn.Option [tlv.Blob ]) (lnwire.MilliSatoshi , bool )
28+ }
29+
30+ // TlvTrafficShaper is an interface that allows the sender to determine if a
31+ // payment should be carried by a channel based on the TLV records that may be
32+ // present in the `update_add_htlc` message or the channel commitment itself.
33+ type TlvTrafficShaper interface {
34+ AuxHtlcModifier
35+
36+ // HandleTraffic is called in order to check if the channel identified
37+ // by the provided channel ID may have external mechanisms that would
38+ // allow it to carry out the payment.
39+ HandleTraffic (cid lnwire.ShortChannelID ,
40+ fundingBlob fn.Option [tlv.Blob ]) (bool , error )
41+
42+ // PaymentBandwidth returns the available bandwidth for a custom channel
43+ // decided by the given channel aux blob and HTLC blob. A return value
44+ // of 0 means there is no bandwidth available. To find out if a channel
45+ // is a custom channel that should be handled by the traffic shaper, the
46+ // HandleTraffic method should be called first.
47+ PaymentBandwidth (htlcBlob ,
48+ commitmentBlob fn.Option [tlv.Blob ]) (lnwire.MilliSatoshi , error )
49+ }
50+
51+ // AuxHtlcModifier is an interface that allows the sender to modify the outgoing
52+ // HTLC of a payment by changing the amount or the wire message tlv records.
53+ type AuxHtlcModifier interface {
54+ // ProduceHtlcExtraData is a function that, based on the previous extra
55+ // data blob of an HTLC, may produce a different blob or modify the
56+ // amount of bitcoin this htlc should carry.
57+ ProduceHtlcExtraData (totalAmount lnwire.MilliSatoshi ,
58+ htlcBlob tlv.Blob ) (btcutil.Amount , tlv.Blob , error )
2259}
2360
2461// getLinkQuery is the function signature used to lookup a link.
@@ -29,8 +66,9 @@ type getLinkQuery func(lnwire.ShortChannelID) (
2966// uses the link lookup provided to query the link for our latest local channel
3067// balances.
3168type bandwidthManager struct {
32- getLink getLinkQuery
33- localChans map [lnwire.ShortChannelID ]struct {}
69+ getLink getLinkQuery
70+ localChans map [lnwire.ShortChannelID ]struct {}
71+ trafficShaper fn.Option [TlvTrafficShaper ]
3472}
3573
3674// newBandwidthManager creates a bandwidth manager for the source node provided
@@ -40,11 +78,13 @@ type bandwidthManager struct {
4078// allows us to reduce the number of extraneous attempts as we can skip channels
4179// that are inactive, or just don't have enough bandwidth to carry the payment.
4280func newBandwidthManager (graph routingGraph , sourceNode route.Vertex ,
43- linkQuery getLinkQuery ) (* bandwidthManager , error ) {
81+ linkQuery getLinkQuery ,
82+ trafficShaper fn.Option [TlvTrafficShaper ]) (* bandwidthManager , error ) {
4483
4584 manager := & bandwidthManager {
46- getLink : linkQuery ,
47- localChans : make (map [lnwire.ShortChannelID ]struct {}),
85+ getLink : linkQuery ,
86+ localChans : make (map [lnwire.ShortChannelID ]struct {}),
87+ trafficShaper : trafficShaper ,
4888 }
4989
5090 // First, we'll collect the set of outbound edges from the target
@@ -71,7 +111,8 @@ func newBandwidthManager(graph routingGraph, sourceNode route.Vertex,
71111// queried is one of our local channels, so any failure to retrieve the link
72112// is interpreted as the link being offline.
73113func (b * bandwidthManager ) getBandwidth (cid lnwire.ShortChannelID ,
74- amount lnwire.MilliSatoshi ) lnwire.MilliSatoshi {
114+ amount lnwire.MilliSatoshi ,
115+ htlcBlob fn.Option [tlv.Blob ]) lnwire.MilliSatoshi {
75116
76117 link , err := b .getLink (cid )
77118 if err != nil {
@@ -89,30 +130,83 @@ func (b *bandwidthManager) getBandwidth(cid lnwire.ShortChannelID,
89130 return 0
90131 }
91132
92- // If our link isn't currently in a state where it can add another
93- // outgoing htlc, treat the link as unusable.
133+ var (
134+ auxBandwidth lnwire.MilliSatoshi
135+ auxBandwidthDetermined bool
136+ )
137+ err = fn .MapOptionZ (b .trafficShaper , func (ts TlvTrafficShaper ) error {
138+ fundingBlob := link .FundingCustomBlob ()
139+ shouldHandle , err := ts .HandleTraffic (cid , fundingBlob )
140+ if err != nil {
141+ return fmt .Errorf ("traffic shaper failed to decide " +
142+ "whether to handle traffic: %w" , err )
143+ }
144+
145+ log .Debugf ("ShortChannelID=%v: external traffic shaper is " +
146+ "handling traffic: %v" , cid , shouldHandle )
147+
148+ // If this channel isn't handled by the external traffic shaper,
149+ // we'll return early.
150+ if ! shouldHandle {
151+ return nil
152+ }
153+
154+ // Ask for a specific bandwidth to be used for the channel.
155+ commitmentBlob := link .CommitmentCustomBlob ()
156+ auxBandwidth , err = ts .PaymentBandwidth (
157+ htlcBlob , commitmentBlob ,
158+ )
159+ if err != nil {
160+ return fmt .Errorf ("failed to get bandwidth from " +
161+ "external traffic shaper: %w" , err )
162+ }
163+
164+ log .Debugf ("ShortChannelID=%v: external traffic shaper " +
165+ "reported available bandwidth: %v" , cid , auxBandwidth )
166+
167+ auxBandwidthDetermined = true
168+
169+ return nil
170+ })
171+ if err != nil {
172+ log .Errorf ("ShortChannelID=%v: failed to get bandwidth from " +
173+ "external traffic shaper: %v" , cid , err )
174+
175+ return 0
176+ }
177+
178+ // If our link isn't currently in a state where it can add
179+ // another outgoing htlc, treat the link as unusable.
94180 if err := link .MayAddOutgoingHtlc (amount ); err != nil {
95- log .Warnf ("ShortChannelID=%v: cannot add outgoing htlc: %v" ,
96- cid , err )
181+ log .Warnf ("ShortChannelID=%v: cannot add outgoing " +
182+ "htlc: %v" , cid , err )
97183 return 0
98184 }
99185
100- // Otherwise, we'll return the current best estimate for the available
101- // bandwidth for the link.
186+ // If the external traffic shaper determined the bandwidth, we'll return
187+ // that value, even if it is zero (which would mean no bandwidth is
188+ // available on that channel).
189+ if auxBandwidthDetermined {
190+ return auxBandwidth
191+ }
192+
193+ // Otherwise, we'll return the current best estimate for the
194+ // available bandwidth for the link.
102195 return link .Bandwidth ()
103196}
104197
105198// availableChanBandwidth returns the total available bandwidth for a channel
106199// and a bool indicating whether the channel hint was found. If the channel is
107200// unavailable, a zero amount is returned.
108201func (b * bandwidthManager ) availableChanBandwidth (channelID uint64 ,
109- amount lnwire.MilliSatoshi ) (lnwire.MilliSatoshi , bool ) {
202+ amount lnwire.MilliSatoshi ,
203+ htlcBlob fn.Option [tlv.Blob ]) (lnwire.MilliSatoshi , bool ) {
110204
111205 shortID := lnwire .NewShortChanIDFromInt (channelID )
112206 _ , ok := b .localChans [shortID ]
113207 if ! ok {
114208 return 0 , false
115209 }
116210
117- return b .getBandwidth (shortID , amount ), true
211+ return b .getBandwidth (shortID , amount , htlcBlob ), true
118212}
0 commit comments