@@ -120,8 +120,8 @@ func (s *AuxTrafficShaper) HandleTraffic(_ lnwire.ShortChannelID,
120120// should be handled by the traffic shaper, the HandleTraffic method should be
121121// called first.
122122func (s * AuxTrafficShaper ) PaymentBandwidth (htlcBlob ,
123- commitmentBlob lfn.Option [tlv.Blob ],
124- linkBandwidth lnwire.MilliSatoshi ) (lnwire.MilliSatoshi , error ) {
123+ commitmentBlob lfn.Option [tlv.Blob ], linkBandwidth ,
124+ htlcAmt lnwire.MilliSatoshi ) (lnwire.MilliSatoshi , error ) {
125125
126126 // If the commitment or HTLC blob is not set, we don't have any
127127 // information about the channel and cannot determine the available
@@ -140,6 +140,28 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
140140 return linkBandwidth , nil
141141 }
142142
143+ // Get the minimum HTLC amount, which is just above dust.
144+ minHtlcAmt := lnwire .NewMSatFromSatoshis (DefaultOnChainHtlcAmount )
145+
146+ // LND calls this hook twice. Once to see if the overall budget of the
147+ // node is enough, and then during pathfinding to actually see if
148+ // there's enough balance in the channel to make the payment attempt.
149+ //
150+ // When doing the overall balance check, we don't know what the actual
151+ // htlcAmt is in satoshis, so a value of 0 will be passed here. Let's at
152+ // least check if we can afford the min amount above dust. If the actual
153+ // htlc amount ends up being greater when calling this method during
154+ // pathfinding, we will still check it below.
155+
156+ // If the passed htlcAmt is below dust, then assume the dust amount. At
157+ // this point we know we are sending assets, so we cannot anchor them to
158+ // dust amounts. Dust HTLCs are added to the fees and aren't
159+ // materialized in an on-chain output, so we wouldn't have anything
160+ // to anchor the asset commitment to.
161+ if htlcAmt < minHtlcAmt {
162+ htlcAmt = minHtlcAmt
163+ }
164+
143165 commitment , err := cmsg .DecodeCommitment (commitmentBytes )
144166 if err != nil {
145167 return 0 , fmt .Errorf ("error decoding commitment blob: %w" , err )
@@ -161,6 +183,14 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
161183 // the amount.
162184 htlcAssetAmount := htlc .Amounts .Val .Sum ()
163185 if htlcAssetAmount != 0 && htlcAssetAmount <= localBalance {
186+ // Check if the current link bandwidth can afford sending out
187+ // the htlc amount without dipping into the channel reserve. If
188+ // it goes below the reserve, we report zero bandwdith as we
189+ // cannot push the htlc amount.
190+ if linkBandwidth < htlcAmt {
191+ return 0 , nil
192+ }
193+
164194 // We signal "infinite" bandwidth by returning a very high
165195 // value (number of Satoshis ever in existence), since we might
166196 // not have a quote available to know what the asset amount
@@ -190,6 +220,14 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
190220
191221 mSatPerAssetUnit := quote .BidPrice
192222
223+ // At this point we have acquired what we need to express the asset
224+ // bandwidth expressed in satoshis. Before we return the result, we need
225+ // to check if the link bandwidth can afford sending a non-dust htlc to
226+ // the other side.
227+ if linkBandwidth < minHtlcAmt {
228+ return 0 , nil
229+ }
230+
193231 // The available balance is the local asset unit expressed in
194232 // milli-satoshis.
195233 return lnwire .MilliSatoshi (localBalance ) * mSatPerAssetUnit , nil
0 commit comments