htlcswitch: handleLocalDispatch can now handle locally sourced resolutions
In this commit, we update the failure case within handleLocalDispatch to handle locally sourced resolutions. This is the case that we send a payment out, but before it can even get past the first hop, we need to go to chain (may have been a cascading failure). Once the HTLC is fully resolved, we’ll send back a resolution message, however, that message doesn’t have a failure reason populated. To properly handle this, we’ll send back a permanent channel failure to the router.
This commit is contained in:
parent
246ba98f47
commit
ca613a625f
@ -479,7 +479,12 @@ func (s *Switch) handleLocalDispatch(packet *htlcPacket) error {
|
|||||||
// user payment and return fail response.
|
// user payment and return fail response.
|
||||||
case *lnwire.UpdateFailHTLC:
|
case *lnwire.UpdateFailHTLC:
|
||||||
var failure *ForwardingError
|
var failure *ForwardingError
|
||||||
if packet.localFailure {
|
switch {
|
||||||
|
|
||||||
|
// The payment never cleared the link, so we don't need to
|
||||||
|
// decrypt the error, simply decode it them report back to the
|
||||||
|
// user.
|
||||||
|
case packet.localFailure:
|
||||||
var userErr string
|
var userErr string
|
||||||
r := bytes.NewReader(htlc.Reason)
|
r := bytes.NewReader(htlc.Reason)
|
||||||
failureMsg, err := lnwire.DecodeFailure(r, 0)
|
failureMsg, err := lnwire.DecodeFailure(r, 0)
|
||||||
@ -494,9 +499,25 @@ func (s *Switch) handleLocalDispatch(packet *htlcPacket) error {
|
|||||||
ExtraMsg: userErr,
|
ExtraMsg: userErr,
|
||||||
FailureMessage: failureMsg,
|
FailureMessage: failureMsg,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// We'll attempt to fully decrypt the onion encrypted error. If
|
// A payment had to be timed out on chain before it got past
|
||||||
// we're unable to then we'll bail early.
|
// 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 packet.isResolution && htlc.Reason == nil:
|
||||||
|
userErr := fmt.Sprintf("payment was resolved " +
|
||||||
|
"on-chain, then cancelled back")
|
||||||
|
failure = &ForwardingError{
|
||||||
|
ErrorSource: s.cfg.SelfKey,
|
||||||
|
ExtraMsg: userErr,
|
||||||
|
FailureMessage: lnwire.FailPermanentChannelFailure{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// A regular multi-hop payment error that we'll need to
|
||||||
|
// decrypt.
|
||||||
|
default:
|
||||||
|
// We'll attempt to fully decrypt the onion encrypted
|
||||||
|
// error. If 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 {
|
||||||
userErr := fmt.Sprintf("unable to de-obfuscate onion failure, "+
|
userErr := fmt.Sprintf("unable to de-obfuscate onion failure, "+
|
||||||
@ -694,16 +715,16 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A blank IncomingChanID in a circuit indicates that it is a pending
|
// A blank IncomingChanID in a circuit indicates that it is a
|
||||||
// user-initiated payment.
|
// pending user-initiated payment.
|
||||||
if packet.incomingChanID == (lnwire.ShortChannelID{}) {
|
if packet.incomingChanID == (lnwire.ShortChannelID{}) {
|
||||||
return s.handleLocalDispatch(packet)
|
return s.handleLocalDispatch(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
source, err := s.getLinkByShortID(packet.incomingChanID)
|
source, err := s.getLinkByShortID(packet.incomingChanID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := errors.Errorf("Unable to get source channel link to "+
|
err := errors.Errorf("Unable to get source channel "+
|
||||||
"forward HTLC settle/fail: %v", err)
|
"link to forward HTLC settle/fail: %v", err)
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user