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:
8 files changed
+185
-79
No files matched your search
+40
-29
@@ -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
|
||||
|
||||
Reference in new issue
Block a user