Skip to content

Commit 9430a70

Browse files
committed
server+tapchannel: always handle traffic for asset HTLCs
This fixes the first part of the issue: We didn't tell lnd that we wanted to handle traffic for non-asset channels. But that's wrong, because then lnd will pick non-asset channels for HTLCs in some situations. So we explicitly need to tell lnd there is no bandwidth in non-asset channels if an asset HTLC should be forwarded (or sent).
1 parent 2e2959e commit 9430a70

File tree

2 files changed

+37
-40
lines changed

2 files changed

+37
-40
lines changed

server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,9 @@ func (s *Server) ShouldHandleTraffic(cid lnwire.ShortChannelID,
10071007
return false, err
10081008
}
10091009

1010-
return s.cfg.AuxTrafficShaper.ShouldHandleTraffic(cid, fundingBlob)
1010+
return s.cfg.AuxTrafficShaper.ShouldHandleTraffic(
1011+
cid, fundingBlob, htlcBlob,
1012+
)
10111013
}
10121014

10131015
// PaymentBandwidth returns the available bandwidth for a custom channel decided

tapchannel/aux_traffic_shaper.go

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -80,27 +80,30 @@ func (s *AuxTrafficShaper) Stop() error {
8080
// it is handled by the traffic shaper, then the normal bandwidth calculation
8181
// can be skipped and the bandwidth returned by PaymentBandwidth should be used
8282
// instead.
83-
func (s *AuxTrafficShaper) ShouldHandleTraffic(_ lnwire.ShortChannelID,
84-
fundingBlob lfn.Option[tlv.Blob]) (bool, error) {
85-
86-
// If there is no auxiliary blob in the channel, it's not a custom
87-
// channel, and we don't need to handle it.
88-
if fundingBlob.IsNone() {
89-
log.Tracef("No aux funding blob set, not handling traffic")
83+
func (s *AuxTrafficShaper) ShouldHandleTraffic(cid lnwire.ShortChannelID,
84+
_, htlcBlob lfn.Option[tlv.Blob]) (bool, error) {
85+
86+
// The rule here is simple: If the HTLC is an asset HTLC, we _need_ to
87+
// handle the bandwidth. Because of non-strict forwarding in lnd, it
88+
// could otherwise be the case that we forward an asset HTLC on a
89+
// non-asset channel, which would be a problem.
90+
htlcBytes := htlcBlob.UnwrapOr(nil)
91+
if len(htlcBytes) == 0 {
92+
log.Tracef("Empty HTLC blob, not handling traffic for %v", cid)
9093
return false, nil
9194
}
9295

93-
// If we can successfully decode the channel blob as a channel capacity
94-
// information, we know that this is a custom channel.
95-
err := lfn.MapOptionZ(fundingBlob, func(blob tlv.Blob) error {
96-
_, err := cmsg.DecodeOpenChannel(blob)
97-
return err
98-
})
99-
if err != nil {
100-
return false, err
96+
// If there are no asset HTLC custom records, we don't need to do
97+
// anything as this is a regular payment.
98+
if !rfqmsg.HasAssetHTLCEntries(htlcBytes) {
99+
log.Tracef("No asset HTLC custom records, not handling "+
100+
"traffic for %v", cid)
101+
return false, nil
101102
}
102103

103-
// No error, so this is a custom channel, we'll want to decide.
104+
// If this _is_ an asset HTLC, we definitely want to handle the
105+
// bandwidth for this channel, so we can deny forwarding asset HTLCs
106+
// over non-asset channels.
104107
return true, nil
105108
}
106109

@@ -114,33 +117,25 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
114117
htlcAmt lnwire.MilliSatoshi,
115118
htlcView lnwallet.AuxHtlcView) (lnwire.MilliSatoshi, error) {
116119

117-
// If the commitment or HTLC blob is not set, we don't have any
118-
// information about the channel and cannot determine the available
119-
// bandwidth from a taproot asset perspective. We return the link
120-
// bandwidth as a fallback.
121-
if commitmentBlob.IsNone() || htlcBlob.IsNone() {
122-
log.Tracef("No commitment or HTLC blob set, returning link "+
123-
"bandwidth %v", linkBandwidth)
124-
return linkBandwidth, nil
125-
}
126-
127-
commitmentBytes := commitmentBlob.UnsafeFromSome()
128-
htlcBytes := htlcBlob.UnsafeFromSome()
120+
htlcBytes := htlcBlob.UnwrapOr(nil)
121+
commitmentBytes := commitmentBlob.UnwrapOr(nil)
129122

130-
// Sometimes the blob is set but actually empty, in which case we also
131-
// don't have any information about the channel.
132-
if len(commitmentBytes) == 0 || len(htlcBytes) == 0 {
133-
log.Tracef("Empty commitment or HTLC blob, returning link "+
134-
"bandwidth %v", linkBandwidth)
123+
// If the HTLC is not an asset HTLC, we can just return the normal link
124+
// bandwidth, as we don't need to do any special math. We shouldn't even
125+
// get here in the first place, since the ShouldHandleTraffic function
126+
// should return false in this case.
127+
if len(htlcBytes) == 0 || !rfqmsg.HasAssetHTLCEntries(htlcBytes) {
128+
log.Tracef("Empty HTLC blob or no asset HTLC custom records, "+
129+
"returning link bandwidth %v", linkBandwidth)
135130
return linkBandwidth, nil
136131
}
137132

138-
// If there are no asset HTLC custom records, we don't need to do
139-
// anything as this is a regular payment.
140-
if !rfqmsg.HasAssetHTLCEntries(htlcBytes) {
141-
log.Tracef("No asset HTLC custom records, returning link "+
142-
"bandwidth %v", linkBandwidth)
143-
return linkBandwidth, nil
133+
// If this is an asset HTLC but the channel is not an asset channel, we
134+
// MUST deny forwarding the HTLC.
135+
if len(commitmentBytes) == 0 {
136+
log.Tracef("Empty commitment blob, cannot forward asset HTLC " +
137+
"over non-asset channel, returning 0 bandwidth")
138+
return 0, nil
144139
}
145140

146141
commitment, err := cmsg.DecodeCommitment(commitmentBytes)

0 commit comments

Comments
 (0)