Skip to content

Commit 6cb374a

Browse files
committed
htlcswitch: add new method handlePacketAdd
Simply moves the code into a new method so it's easier to follow the method `handlePacketForward`.
1 parent d28d5d7 commit 6cb374a

File tree

1 file changed

+178
-179
lines changed

1 file changed

+178
-179
lines changed

htlcswitch/switch.go

Lines changed: 178 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,185 +1104,7 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
11041104
// payment circuit within our internal state so we can properly forward
11051105
// the ultimate settle message back latter.
11061106
case *lnwire.UpdateAddHTLC:
1107-
// Check if the node is set to reject all onward HTLCs and also make
1108-
// sure that HTLC is not from the source node.
1109-
if s.cfg.RejectHTLC {
1110-
failure := NewDetailedLinkError(
1111-
&lnwire.FailChannelDisabled{},
1112-
OutgoingFailureForwardsDisabled,
1113-
)
1114-
1115-
return s.failAddPacket(packet, failure)
1116-
}
1117-
1118-
// Before we attempt to find a non-strict forwarding path for
1119-
// this htlc, check whether the htlc is being routed over the
1120-
// same incoming and outgoing channel. If our node does not
1121-
// allow forwards of this nature, we fail the htlc early. This
1122-
// check is in place to disallow inefficiently routed htlcs from
1123-
// locking up our balance. With channels where the
1124-
// option-scid-alias feature was negotiated, we also have to be
1125-
// sure that the IDs aren't the same since one or both could be
1126-
// an alias.
1127-
linkErr := s.checkCircularForward(
1128-
packet.incomingChanID, packet.outgoingChanID,
1129-
s.cfg.AllowCircularRoute, htlc.PaymentHash,
1130-
)
1131-
if linkErr != nil {
1132-
return s.failAddPacket(packet, linkErr)
1133-
}
1134-
1135-
s.indexMtx.RLock()
1136-
targetLink, err := s.getLinkByMapping(packet)
1137-
if err != nil {
1138-
s.indexMtx.RUnlock()
1139-
1140-
log.Debugf("unable to find link with "+
1141-
"destination %v", packet.outgoingChanID)
1142-
1143-
// If packet was forwarded from another channel link
1144-
// than we should notify this link that some error
1145-
// occurred.
1146-
linkError := NewLinkError(
1147-
&lnwire.FailUnknownNextPeer{},
1148-
)
1149-
1150-
return s.failAddPacket(packet, linkError)
1151-
}
1152-
targetPeerKey := targetLink.PeerPubKey()
1153-
interfaceLinks, _ := s.getLinks(targetPeerKey)
1154-
s.indexMtx.RUnlock()
1155-
1156-
// We'll keep track of any HTLC failures during the link
1157-
// selection process. This way we can return the error for
1158-
// precise link that the sender selected, while optimistically
1159-
// trying all links to utilize our available bandwidth.
1160-
linkErrs := make(map[lnwire.ShortChannelID]*LinkError)
1161-
1162-
// Find all destination channel links with appropriate
1163-
// bandwidth.
1164-
var destinations []ChannelLink
1165-
for _, link := range interfaceLinks {
1166-
var failure *LinkError
1167-
1168-
// We'll skip any links that aren't yet eligible for
1169-
// forwarding.
1170-
if !link.EligibleToForward() {
1171-
failure = NewDetailedLinkError(
1172-
&lnwire.FailUnknownNextPeer{},
1173-
OutgoingFailureLinkNotEligible,
1174-
)
1175-
} else {
1176-
// We'll ensure that the HTLC satisfies the
1177-
// current forwarding conditions of this target
1178-
// link.
1179-
currentHeight := atomic.LoadUint32(&s.bestHeight)
1180-
failure = link.CheckHtlcForward(
1181-
htlc.PaymentHash, packet.incomingAmount,
1182-
packet.amount, packet.incomingTimeout,
1183-
packet.outgoingTimeout,
1184-
packet.inboundFee,
1185-
currentHeight,
1186-
packet.originalOutgoingChanID,
1187-
)
1188-
}
1189-
1190-
// If this link can forward the htlc, add it to the set
1191-
// of destinations.
1192-
if failure == nil {
1193-
destinations = append(destinations, link)
1194-
continue
1195-
}
1196-
1197-
linkErrs[link.ShortChanID()] = failure
1198-
}
1199-
1200-
// If we had a forwarding failure due to the HTLC not
1201-
// satisfying the current policy, then we'll send back an
1202-
// error, but ensure we send back the error sourced at the
1203-
// *target* link.
1204-
if len(destinations) == 0 {
1205-
// At this point, some or all of the links rejected the
1206-
// HTLC so we couldn't forward it. So we'll try to look
1207-
// up the error that came from the source.
1208-
linkErr, ok := linkErrs[packet.outgoingChanID]
1209-
if !ok {
1210-
// If we can't find the error of the source,
1211-
// then we'll return an unknown next peer,
1212-
// though this should never happen.
1213-
linkErr = NewLinkError(
1214-
&lnwire.FailUnknownNextPeer{},
1215-
)
1216-
log.Warnf("unable to find err source for "+
1217-
"outgoing_link=%v, errors=%v",
1218-
packet.outgoingChanID,
1219-
lnutils.SpewLogClosure(linkErrs))
1220-
}
1221-
1222-
log.Tracef("incoming HTLC(%x) violated "+
1223-
"target outgoing link (id=%v) policy: %v",
1224-
htlc.PaymentHash[:], packet.outgoingChanID,
1225-
linkErr)
1226-
1227-
return s.failAddPacket(packet, linkErr)
1228-
}
1229-
1230-
// Choose a random link out of the set of links that can forward
1231-
// this htlc. The reason for randomization is to evenly
1232-
// distribute the htlc load without making assumptions about
1233-
// what the best channel is.
1234-
destination := destinations[rand.Intn(len(destinations))] // nolint:gosec
1235-
1236-
// Retrieve the incoming link by its ShortChannelID. Note that
1237-
// the incomingChanID is never set to hop.Source here.
1238-
s.indexMtx.RLock()
1239-
incomingLink, err := s.getLinkByShortID(packet.incomingChanID)
1240-
s.indexMtx.RUnlock()
1241-
if err != nil {
1242-
// If we couldn't find the incoming link, we can't
1243-
// evaluate the incoming's exposure to dust, so we just
1244-
// fail the HTLC back.
1245-
linkErr := NewLinkError(
1246-
&lnwire.FailTemporaryChannelFailure{},
1247-
)
1248-
1249-
return s.failAddPacket(packet, linkErr)
1250-
}
1251-
1252-
// Evaluate whether this HTLC would increase our fee exposure
1253-
// over the threshold on the incoming link. If it does, fail it
1254-
// backwards.
1255-
if s.dustExceedsFeeThreshold(
1256-
incomingLink, packet.incomingAmount, true,
1257-
) {
1258-
// The incoming dust exceeds the threshold, so we fail
1259-
// the add back.
1260-
linkErr := NewLinkError(
1261-
&lnwire.FailTemporaryChannelFailure{},
1262-
)
1263-
1264-
return s.failAddPacket(packet, linkErr)
1265-
}
1266-
1267-
// Also evaluate whether this HTLC would increase our fee
1268-
// exposure over the threshold on the destination link. If it
1269-
// does, fail it back.
1270-
if s.dustExceedsFeeThreshold(
1271-
destination, packet.amount, false,
1272-
) {
1273-
// The outgoing dust exceeds the threshold, so we fail
1274-
// the add back.
1275-
linkErr := NewLinkError(
1276-
&lnwire.FailTemporaryChannelFailure{},
1277-
)
1278-
1279-
return s.failAddPacket(packet, linkErr)
1280-
}
1281-
1282-
// Send the packet to the destination channel link which
1283-
// manages the channel.
1284-
packet.outgoingChanID = destination.ShortChanID()
1285-
return destination.handleSwitchPacket(packet)
1107+
return s.handlePacketAdd(packet, htlc)
12861108

12871109
case *lnwire.UpdateFailHTLC, *lnwire.UpdateFulfillHTLC:
12881110
// If the source of this packet has not been set, use the
@@ -3052,3 +2874,180 @@ func (s *Switch) AddAliasForLink(chanID lnwire.ChannelID,
30522874

30532875
return nil
30542876
}
2877+
2878+
// handlePacketAdd handles forwarding an Add packet.
2879+
func (s *Switch) handlePacketAdd(packet *htlcPacket,
2880+
htlc *lnwire.UpdateAddHTLC) error {
2881+
2882+
// Check if the node is set to reject all onward HTLCs and also make
2883+
// sure that HTLC is not from the source node.
2884+
if s.cfg.RejectHTLC {
2885+
failure := NewDetailedLinkError(
2886+
&lnwire.FailChannelDisabled{},
2887+
OutgoingFailureForwardsDisabled,
2888+
)
2889+
2890+
return s.failAddPacket(packet, failure)
2891+
}
2892+
2893+
// Before we attempt to find a non-strict forwarding path for this
2894+
// htlc, check whether the htlc is being routed over the same incoming
2895+
// and outgoing channel. If our node does not allow forwards of this
2896+
// nature, we fail the htlc early. This check is in place to disallow
2897+
// inefficiently routed htlcs from locking up our balance. With
2898+
// channels where the option-scid-alias feature was negotiated, we also
2899+
// have to be sure that the IDs aren't the same since one or both could
2900+
// be an alias.
2901+
linkErr := s.checkCircularForward(
2902+
packet.incomingChanID, packet.outgoingChanID,
2903+
s.cfg.AllowCircularRoute, htlc.PaymentHash,
2904+
)
2905+
if linkErr != nil {
2906+
return s.failAddPacket(packet, linkErr)
2907+
}
2908+
2909+
s.indexMtx.RLock()
2910+
targetLink, err := s.getLinkByMapping(packet)
2911+
if err != nil {
2912+
s.indexMtx.RUnlock()
2913+
2914+
log.Debugf("unable to find link with "+
2915+
"destination %v", packet.outgoingChanID)
2916+
2917+
// If packet was forwarded from another channel link than we
2918+
// should notify this link that some error occurred.
2919+
linkError := NewLinkError(
2920+
&lnwire.FailUnknownNextPeer{},
2921+
)
2922+
2923+
return s.failAddPacket(packet, linkError)
2924+
}
2925+
targetPeerKey := targetLink.PeerPubKey()
2926+
interfaceLinks, _ := s.getLinks(targetPeerKey)
2927+
s.indexMtx.RUnlock()
2928+
2929+
// We'll keep track of any HTLC failures during the link selection
2930+
// process. This way we can return the error for precise link that the
2931+
// sender selected, while optimistically trying all links to utilize
2932+
// our available bandwidth.
2933+
linkErrs := make(map[lnwire.ShortChannelID]*LinkError)
2934+
2935+
// Find all destination channel links with appropriate bandwidth.
2936+
var destinations []ChannelLink
2937+
for _, link := range interfaceLinks {
2938+
var failure *LinkError
2939+
2940+
// We'll skip any links that aren't yet eligible for
2941+
// forwarding.
2942+
if !link.EligibleToForward() {
2943+
failure = NewDetailedLinkError(
2944+
&lnwire.FailUnknownNextPeer{},
2945+
OutgoingFailureLinkNotEligible,
2946+
)
2947+
} else {
2948+
// We'll ensure that the HTLC satisfies the current
2949+
// forwarding conditions of this target link.
2950+
currentHeight := atomic.LoadUint32(&s.bestHeight)
2951+
failure = link.CheckHtlcForward(
2952+
htlc.PaymentHash, packet.incomingAmount,
2953+
packet.amount, packet.incomingTimeout,
2954+
packet.outgoingTimeout,
2955+
packet.inboundFee,
2956+
currentHeight,
2957+
packet.originalOutgoingChanID,
2958+
)
2959+
}
2960+
2961+
// If this link can forward the htlc, add it to the set of
2962+
// destinations.
2963+
if failure == nil {
2964+
destinations = append(destinations, link)
2965+
continue
2966+
}
2967+
2968+
linkErrs[link.ShortChanID()] = failure
2969+
}
2970+
2971+
// If we had a forwarding failure due to the HTLC not satisfying the
2972+
// current policy, then we'll send back an error, but ensure we send
2973+
// back the error sourced at the *target* link.
2974+
if len(destinations) == 0 {
2975+
// At this point, some or all of the links rejected the HTLC so
2976+
// we couldn't forward it. So we'll try to look up the error
2977+
// that came from the source.
2978+
linkErr, ok := linkErrs[packet.outgoingChanID]
2979+
if !ok {
2980+
// If we can't find the error of the source, then we'll
2981+
// return an unknown next peer, though this should
2982+
// never happen.
2983+
linkErr = NewLinkError(
2984+
&lnwire.FailUnknownNextPeer{},
2985+
)
2986+
log.Warnf("unable to find err source for "+
2987+
"outgoing_link=%v, errors=%v",
2988+
packet.outgoingChanID,
2989+
lnutils.SpewLogClosure(linkErrs))
2990+
}
2991+
2992+
log.Tracef("incoming HTLC(%x) violated "+
2993+
"target outgoing link (id=%v) policy: %v",
2994+
htlc.PaymentHash[:], packet.outgoingChanID,
2995+
linkErr)
2996+
2997+
return s.failAddPacket(packet, linkErr)
2998+
}
2999+
3000+
// Choose a random link out of the set of links that can forward this
3001+
// htlc. The reason for randomization is to evenly distribute the htlc
3002+
// load without making assumptions about what the best channel is.
3003+
destination := destinations[rand.Intn(len(destinations))] // nolint:gosec
3004+
3005+
// Retrieve the incoming link by its ShortChannelID. Note that the
3006+
// incomingChanID is never set to hop.Source here.
3007+
s.indexMtx.RLock()
3008+
incomingLink, err := s.getLinkByShortID(packet.incomingChanID)
3009+
s.indexMtx.RUnlock()
3010+
if err != nil {
3011+
// If we couldn't find the incoming link, we can't evaluate the
3012+
// incoming's exposure to dust, so we just fail the HTLC back.
3013+
linkErr := NewLinkError(
3014+
&lnwire.FailTemporaryChannelFailure{},
3015+
)
3016+
3017+
return s.failAddPacket(packet, linkErr)
3018+
}
3019+
3020+
// Evaluate whether this HTLC would increase our fee exposure over the
3021+
// threshold on the incoming link. If it does, fail it backwards.
3022+
if s.dustExceedsFeeThreshold(
3023+
incomingLink, packet.incomingAmount, true,
3024+
) {
3025+
// The incoming dust exceeds the threshold, so we fail the add
3026+
// back.
3027+
linkErr := NewLinkError(
3028+
&lnwire.FailTemporaryChannelFailure{},
3029+
)
3030+
3031+
return s.failAddPacket(packet, linkErr)
3032+
}
3033+
3034+
// Also evaluate whether this HTLC would increase our fee exposure over
3035+
// the threshold on the destination link. If it does, fail it back.
3036+
if s.dustExceedsFeeThreshold(
3037+
destination, packet.amount, false,
3038+
) {
3039+
// The outgoing dust exceeds the threshold, so we fail the add
3040+
// back.
3041+
linkErr := NewLinkError(
3042+
&lnwire.FailTemporaryChannelFailure{},
3043+
)
3044+
3045+
return s.failAddPacket(packet, linkErr)
3046+
}
3047+
3048+
// Send the packet to the destination channel link which manages the
3049+
// channel.
3050+
packet.outgoingChanID = destination.ShortChanID()
3051+
3052+
return destination.handleSwitchPacket(packet)
3053+
}

0 commit comments

Comments
 (0)