htlcswitch: use LinkError for internal errors

Update the ChannelLink interface to specifically
return the LinkError struct. This error implements
the ClearTextError interface, so will be picked
up as a routing realted error by the router.

With LinkErrors implemented, the switch now
returns a LinkError for all failures on our
incoming/outgoing link and ForwardingError when
the failure occurs down the line.
This commit is contained in:
carla committed 2020-01-14 15:21:15 +02:00
1 parent b5a2d75465
commit f430fd50c5
8 files changed
+185 -79

No files matched your search

+40 -29
View File
@@ -756,20 +756,19 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
s.indexMtx.RUnlock()
if err != nil {
log.Errorf("Link %v not found", pkt.outgoingChanID)
return NewForwardingError(
&lnwire.FailUnknownNextPeer{}, 0, "",
)
return NewLinkError(&lnwire.FailUnknownNextPeer{})
}
if !link.EligibleToForward() {
err := fmt.Errorf("Link %v is not available to forward",
log.Errorf("Link %v is not available to forward",
pkt.outgoingChanID)
log.Error(err)
// The update does not need to be populated as the error
// will be returned back to the router.
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
return NewForwardingError(htlcErr, 0, err.Error())
return NewDetailedLinkError(
lnwire.NewTemporaryChannelFailure(nil),
FailureDetailLinkNotEligible,
)
}
// Ensure that the htlc satisfies the outgoing channel policy.
@@ -782,8 +781,7 @@ func (s *Switch) handleLocalDispatch(pkt *htlcPacket) error {
if htlcErr != nil {
log.Errorf("Link %v policy for local forward not "+
"satisfied", pkt.outgoingChanID)
return NewForwardingError(htlcErr, 0, "")
return htlcErr
}
return link.HandleSwitchPacket(pkt)
@@ -907,35 +905,43 @@ func (s *Switch) parseFailedPayment(deobfuscator ErrorDecrypter,
// decrypt the error, simply decode it them report back to the
// user.
case unencrypted:
var userErr string
r := bytes.NewReader(htlc.Reason)
failureMsg, err := lnwire.DecodeFailure(r, 0)
if err != nil {
userErr = fmt.Sprintf("unable to decode onion "+
"failure (hash=%v, pid=%d): %v",
paymentHash, paymentID, err)
log.Error(userErr)
// If we could not decode the failure reason, return a link
// error indicating that we failed to decode the onion.
linkError := NewDetailedLinkError(
// As this didn't even clear the link, we don't
// need to apply an update here since it goes
// directly to the router.
lnwire.NewTemporaryChannelFailure(nil),
FailureDetailOnionDecode,
)
// As this didn't even clear the link, we don't need to
// apply an update here since it goes directly to the
// router.
failureMsg = lnwire.NewTemporaryChannelFailure(nil)
log.Errorf("%v: (hash=%v, pid=%d): %v",
linkError.FailureDetail, paymentHash, paymentID,
err)
return linkError
}
return NewForwardingError(failureMsg, 0, userErr)
// If we successfully decoded the failure reason, return it.
return NewLinkError(failureMsg)
// A payment had to be timed out on chain before it got past
// the first hop. In this case, we'll report a permanent
// channel failure as this means us, or the remote party had to
// go on chain.
case isResolution && htlc.Reason == nil:
userErr := fmt.Sprintf("payment was resolved "+
"on-chain, then canceled back (hash=%v, pid=%d)",
linkError := NewDetailedLinkError(
&lnwire.FailPermanentChannelFailure{},
FailureDetailOnChainTimeout,
)
log.Info("%v: hash=%v, pid=%d", linkError.FailureDetail,
paymentHash, paymentID)
return NewForwardingError(
&lnwire.FailPermanentChannelFailure{}, 0, userErr,
)
return linkError
// A regular multi-hop payment error that we'll need to
// decrypt.
@@ -1002,18 +1008,21 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
// selection process. This way we can return the error for
// precise link that the sender selected, while optimistically
// trying all links to utilize our available bandwidth.
linkErrs := make(map[lnwire.ShortChannelID]lnwire.FailureMessage)
linkErrs := make(map[lnwire.ShortChannelID]*LinkError)
// Try to find destination channel link with appropriate
// bandwidth.
var destination ChannelLink
for _, link := range interfaceLinks {
var failure lnwire.FailureMessage
var failure *LinkError
// We'll skip any links that aren't yet eligible for
// forwarding.
if !link.EligibleToForward() {
failure = &lnwire.FailUnknownNextPeer{}
failure = NewDetailedLinkError(
&lnwire.FailUnknownNextPeer{},
FailureDetailLinkNotEligible,
)
} else {
// We'll ensure that the HTLC satisfies the
// current forwarding conditions of this target
@@ -1048,7 +1057,9 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
// If we can't find the error of the source,
// then we'll return an unknown next peer,
// though this should never happen.
linkErr = &lnwire.FailUnknownNextPeer{}
linkErr = NewLinkError(
&lnwire.FailUnknownNextPeer{},
)
log.Warnf("unable to find err source for "+
"outgoing_link=%v, errors=%v",
packet.outgoingChanID, newLogClosure(func() string {
@@ -1061,7 +1072,7 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
htlc.PaymentHash[:], packet.outgoingChanID,
linkErr)
return s.failAddPacket(packet, linkErr, addErr)
return s.failAddPacket(packet, linkErr.WireMessage(), addErr)
}
// Send the packet to the destination channel link which