Skip to content

Commit 4d4bf55

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 b7e6907 commit 4d4bf55

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

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)