@@ -174,18 +174,40 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
174174 return 0 , fmt .Errorf ("error decoding HTLC blob: %w" , err )
175175 }
176176
177- // localBalance is the total number of local asset units.
178- localBalance := cmsg . OutputSum ( commitment . LocalOutputs ())
179-
180- // There either already is an amount set in the HTLC (which would
181- // indicate it to be a direct-channel keysend payment that just sends
182- // assets to the direct peer with no conversion), in which case we don't
183- // need an RFQ ID as we can just compare the local balance and the
184- // required HTLC amount. If there is no amount set, we need to look up
185- // the RFQ ID in the HTLC blob and use the accepted quote to determine
186- // the amount .
177+ // With the help of the latest HtlcView, let's calculate a more precise
178+ // local balance. This is useful in order to not forward HTLCs that may
179+ // never be settled. Other HTLCs that may also call into this method are
180+ // not yet registered to the commitment, so we need to account for them
181+ // manually.
182+ computedLocal := ComputeLocalBalance ( commitment )
183+
184+ // If the HTLC carries asset units (keysend, forwarding), then there's
185+ // no need to do any RFQ related math. We can directly compare the asset
186+ // units of the HTLC with those in our local balance .
187187 htlcAssetAmount := htlc .Amounts .Val .Sum ()
188- if htlcAssetAmount != 0 && htlcAssetAmount <= localBalance {
188+ if htlcAssetAmount != 0 {
189+ return paymentBandwidthAssetUnits (
190+ htlcAssetAmount , computedLocal , linkBandwidth , htlcAmt ,
191+ )
192+ }
193+
194+ // Otherwise, we derive the available bandwidth from the HTLC's RFQ and
195+ // the asset units in our local balance.
196+ return s .paymentBandwidthRfqMath (
197+ htlc , computedLocal , linkBandwidth , minHtlcAmt ,
198+ )
199+ }
200+
201+ // paymentBandwidthAssetUnits includes the asset unit related checks between the
202+ // HTLC carrying the units and the asset balance of our channel. The response
203+ // will either be infinite or zero bandwidth, as we can't really map the amount
204+ // to msats without an RFQ, and it's also not needed.
205+ func paymentBandwidthAssetUnits (htlcAssetAmount , computedLocal uint64 ,
206+ linkBandwidth ,
207+ htlcAmt lnwire.MilliSatoshi ) (lnwire.MilliSatoshi , error ) {
208+
209+ switch {
210+ case htlcAssetAmount <= computedLocal :
189211 // Check if the current link bandwidth can afford sending out
190212 // the htlc amount without dipping into the channel reserve. If
191213 // it goes below the reserve, we report zero bandwidth as we
@@ -204,10 +226,29 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
204226 // matter too much here, we just want to signal that this
205227 // channel _does_ have available bandwidth.
206228 return lnwire .NewMSatFromSatoshis (btcutil .MaxSatoshi ), nil
229+
230+ case htlcAssetAmount > computedLocal :
231+ // The asset balance of the channel is simply not enough to
232+ // route the asset units, we report 0 bandwidth in order for the
233+ // HTLC to fail back.
234+ return 0 , nil
235+
236+ default :
237+ // We shouldn't reach this case, we add it only for the function
238+ // to always return something and the compiler to be happy.
239+ return 0 , nil
207240 }
241+ }
208242
209- // If the HTLC doesn't have an asset amount and RFQ ID, it's incomplete,
210- // and we cannot determine what channel to use.
243+ // paymentBandwidthRfqMath returns the available payment bandwidth of the
244+ // channel based on the asset rate of the RFQ quote that is included in the
245+ // HTLC and the asset units of the local balance.
246+ func (s * AuxTrafficShaper ) paymentBandwidthRfqMath (htlc * rfqmsg.Htlc ,
247+ localBalance uint64 , linkBandwidth ,
248+ minHtlcAmt lnwire.MilliSatoshi ) (lnwire.MilliSatoshi , error ) {
249+
250+ // If the HTLC doesn't have an RFQ ID, it's incomplete, and we cannot
251+ // determine the bandwidth.
211252 if htlc .RfqID .ValOpt ().IsNone () {
212253 log .Tracef ("No RFQ ID in HTLC, cannot determine matching " +
213254 "outgoing channel" )
@@ -261,6 +302,16 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
261302 return availableBalanceMsat , nil
262303}
263304
305+ // ComputeLocalBalance combines the given commitment state with the HtlcView to
306+ // produce the available local balance with accuracy.
307+ func ComputeLocalBalance (commitment * cmsg.Commitment ) uint64 {
308+ // Let's get the current local asset balance of the channel as reported
309+ // by the latest commitment.
310+ localBalance := cmsg .OutputSum (commitment .LocalOutputs ())
311+
312+ return localBalance
313+ }
314+
264315// ProduceHtlcExtraData is a function that, based on the previous custom record
265316// blob of an HTLC, may produce a different blob or modify the amount of bitcoin
266317// this HTLC should carry.
0 commit comments