diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 254b56f8c..2dd7ce2c0 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -1936,69 +1936,11 @@ func (l *channelLink) handleUpstreamMsg(ctx context.Context, } case *lnwire.UpdateFailMalformedHTLC: - // Convert the failure type encoded within the HTLC fail - // message to the proper generic lnwire error code. - var failure lnwire.FailureMessage - switch msg.FailureCode { - case lnwire.CodeInvalidOnionVersion: - failure = &lnwire.FailInvalidOnionVersion{ - OnionSHA256: msg.ShaOnionBlob, - } - case lnwire.CodeInvalidOnionHmac: - failure = &lnwire.FailInvalidOnionHmac{ - OnionSHA256: msg.ShaOnionBlob, - } - - case lnwire.CodeInvalidOnionKey: - failure = &lnwire.FailInvalidOnionKey{ - OnionSHA256: msg.ShaOnionBlob, - } - - // Handle malformed errors that are part of a blinded route. - // This case is slightly different, because we expect every - // relaying node in the blinded portion of the route to send - // malformed errors. If we're also a relaying node, we're - // likely going to switch this error out anyway for our own - // malformed error, but we handle the case here for - // completeness. - case lnwire.CodeInvalidBlinding: - failure = &lnwire.FailInvalidBlinding{ - OnionSHA256: msg.ShaOnionBlob, - } - - default: - l.log.Warnf("unexpected failure code received in "+ - "UpdateFailMailformedHTLC: %v", msg.FailureCode) - - // We don't just pass back the error we received from - // our successor. Otherwise we might report a failure - // that penalizes us more than needed. If the onion that - // we forwarded was correct, the node should have been - // able to send back its own failure. The node did not - // send back its own failure, so we assume there was a - // problem with the onion and report that back. We reuse - // the invalid onion key failure because there is no - // specific error for this case. - failure = &lnwire.FailInvalidOnionKey{ - OnionSHA256: msg.ShaOnionBlob, - } - } - - // With the error parsed, we'll convert the into it's opaque - // form. - var b bytes.Buffer - if err := lnwire.EncodeFailure(&b, failure, 0); err != nil { - l.log.Errorf("unable to encode malformed error: %v", err) - return - } - - // If remote side have been unable to parse the onion blob we - // have sent to it, than we should transform the malformed HTLC - // message to the usual HTLC fail message. - err := l.channel.ReceiveFailHTLC(msg.ID, b.Bytes()) + err := l.processRemoteUpdateFailMalformedHTLC(msg) if err != nil { - l.failf(LinkFailureError{code: ErrInvalidUpdate}, - "unable to handle upstream fail HTLC: %v", err) + l.log.Errorf("failed to process remote fail "+ + "malformed: %v", err) + return } @@ -4671,3 +4613,74 @@ func (l *channelLink) processRemoteUpdateFulfillHTLC( return nil } + +// processRemoteUpdateFailMalformedHTLC takes an `UpdateFailMalformedHTLC` msg +// sent from the remote and processes it. +func (l *channelLink) processRemoteUpdateFailMalformedHTLC( + msg *lnwire.UpdateFailMalformedHTLC) error { + + // Convert the failure type encoded within the HTLC fail message to the + // proper generic lnwire error code. + var failure lnwire.FailureMessage + switch msg.FailureCode { + case lnwire.CodeInvalidOnionVersion: + failure = &lnwire.FailInvalidOnionVersion{ + OnionSHA256: msg.ShaOnionBlob, + } + case lnwire.CodeInvalidOnionHmac: + failure = &lnwire.FailInvalidOnionHmac{ + OnionSHA256: msg.ShaOnionBlob, + } + + case lnwire.CodeInvalidOnionKey: + failure = &lnwire.FailInvalidOnionKey{ + OnionSHA256: msg.ShaOnionBlob, + } + + // Handle malformed errors that are part of a blinded route. This case + // is slightly different, because we expect every relaying node in the + // blinded portion of the route to send malformed errors. If we're also + // a relaying node, we're likely going to switch this error out anyway + // for our own malformed error, but we handle the case here for + // completeness. + case lnwire.CodeInvalidBlinding: + failure = &lnwire.FailInvalidBlinding{ + OnionSHA256: msg.ShaOnionBlob, + } + + default: + l.log.Warnf("unexpected failure code received in "+ + "UpdateFailMailformedHTLC: %v", msg.FailureCode) + + // We don't just pass back the error we received from our + // successor. Otherwise we might report a failure that penalizes + // us more than needed. If the onion that we forwarded was + // correct, the node should have been able to send back its own + // failure. The node did not send back its own failure, so we + // assume there was a problem with the onion and report that + // back. We reuse the invalid onion key failure because there is + // no specific error for this case. + failure = &lnwire.FailInvalidOnionKey{ + OnionSHA256: msg.ShaOnionBlob, + } + } + + // With the error parsed, we'll convert the into it's opaque form. + var b bytes.Buffer + if err := lnwire.EncodeFailure(&b, failure, 0); err != nil { + return fmt.Errorf("unable to encode malformed error: %w", err) + } + + // If remote side have been unable to parse the onion blob we have sent + // to it, than we should transform the malformed HTLC message to the + // usual HTLC fail message. + err := l.channel.ReceiveFailHTLC(msg.ID, b.Bytes()) + if err != nil { + l.failf(LinkFailureError{code: ErrInvalidUpdate}, + "unable to handle upstream fail HTLC: %v", err) + + return err + } + + return nil +}