htlcswitch: always return an instance of ForwardingError from handleLocalDispatch

This commit modifies the errors that we return within the
handleLocalDispatch method. Rather than returning a regular error, or
simply the matching error code in some instances, we now _always_
return an instance of ForwardingError. This will allow the router to
make more intelligent decisions w.r.t routing HTLC’s as with this
information it will now be able to differentiate errors that occur
within the switch (before sending out the HTLC), from errors that occur
within the HTLC route itself.
This commit is contained in:
Olaoluwa Osuntokun 2017-10-16 18:42:11 -07:00
parent 61be23dc31
commit 65c03c98d0
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

@ -320,10 +320,10 @@ func (s *Switch) forward(packet *htlcPacket) error {
} }
} }
// handleLocalDispatch is used at the start/end of the htlc update life // handleLocalDispatch is used at the start/end of the htlc update life cycle.
// cycle. At the start (1) it is used to send the htlc to the channel link // At the start (1) it is used to send the htlc to the channel link without
// without creation of circuit. At the end (2) it is used to notify the user // creation of circuit. At the end (2) it is used to notify the user about the
// about the result of his payment is it was successful or not. // result of his payment is it was successful or not.
// //
// Alice Bob Carol // Alice Bob Carol
// o --add----> o ---add----> o // o --add----> o ---add----> o
@ -342,9 +342,11 @@ func (s *Switch) handleLocalDispatch(payment *pendingPayment, packet *htlcPacket
// Try to find links by node destination. // Try to find links by node destination.
links, err := s.getLinks(packet.destNode) links, err := s.getLinks(packet.destNode)
if err != nil { if err != nil {
log.Errorf("unable to find links by "+ log.Errorf("unable to find links by destination %v", err)
"destination %v", err) return &ForwardingError{
return errors.New(lnwire.CodeUnknownNextPeer) ErrorSource: s.cfg.SelfKey,
FailureMessage: &lnwire.FailUnknownNextPeer{},
}
} }
// Try to find destination channel link with appropriate // Try to find destination channel link with appropriate
@ -373,19 +375,26 @@ func (s *Switch) handleLocalDispatch(payment *pendingPayment, packet *htlcPacket
"outgoing links: need %v, max available is %v", "outgoing links: need %v, max available is %v",
htlc.Amount, largestBandwidth) htlc.Amount, largestBandwidth)
log.Error(err) log.Error(err)
return err
htlcErr := lnwire.NewTemporaryChannelFailure(nil)
return &ForwardingError{
ErrorSource: s.cfg.SelfKey,
ExtraMsg: err.Error(),
FailureMessage: htlcErr,
}
} }
// Send the packet to the destination channel link which // Send the packet to the destination channel link which
// manages then channel. // manages then channel.
//
// TODO(roasbeef): should return with an error
destination.HandleSwitchPacket(packet) destination.HandleSwitchPacket(packet)
return nil return nil
// We've just received a settle update which means we can finalize // We've just received a settle update which means we can finalize the
// the user payment and return successful response. // user payment and return successful response.
case *lnwire.UpdateFufillHTLC: case *lnwire.UpdateFufillHTLC:
// Notify the user that his payment was // Notify the user that his payment was successfully proceed.
// successfully proceed.
payment.err <- nil payment.err <- nil
payment.preimage <- htlc.PaymentPreimage payment.preimage <- htlc.PaymentPreimage
s.removePendingPayment(payment.amount, payment.paymentHash) s.removePendingPayment(payment.amount, payment.paymentHash)
@ -393,23 +402,19 @@ func (s *Switch) handleLocalDispatch(payment *pendingPayment, packet *htlcPacket
// We've just received a fail update which means we can finalize the // We've just received a fail update which means we can finalize the
// user payment and return fail response. // user payment and return fail response.
case *lnwire.UpdateFailHTLC: case *lnwire.UpdateFailHTLC:
var userErr error
// We'll attempt to fully decrypt the onion encrypted error. If // We'll attempt to fully decrypt the onion encrypted error. If
// we're unable to then we'll bail early. // we're unable to then we'll bail early.
failure, err := payment.deobfuscator.DecryptError(htlc.Reason) failure, err := payment.deobfuscator.DecryptError(htlc.Reason)
if err != nil { if err != nil {
// TODO(roasbeef): can happen in case of local error in userErr := fmt.Sprintf("unable to de-obfuscate "+
// link pkt handling
userErr = errors.Errorf("unable to de-obfuscate "+
"onion failure, htlc with hash(%x): %v", "onion failure, htlc with hash(%x): %v",
payment.paymentHash[:], err) payment.paymentHash[:], err)
log.Error(userErr) log.Error(userErr)
} payment.err <- &ForwardingError{
ErrorSource: s.cfg.SelfKey,
// Notify user that his payment was discarded. ExtraMsg: userErr,
if userErr != nil { FailureMessage: lnwire.NewTemporaryChannelFailure(nil),
payment.err <- userErr }
} else { } else {
payment.err <- failure payment.err <- failure
} }