mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-10 17:01:32 +02:00
htlcswitch: convert blinded failures for blinded payments
This commit is contained in:
parent
de9c9c028c
commit
43687181f7
@ -39,6 +39,12 @@ const (
|
|||||||
EncrypterTypeRelaying = 4
|
EncrypterTypeRelaying = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IsBlinded returns a boolean indicating whether the error encrypter belongs
|
||||||
|
// to a blinded route.
|
||||||
|
func (e EncrypterType) IsBlinded() bool {
|
||||||
|
return e == EncrypterTypeIntroduction || e == EncrypterTypeRelaying
|
||||||
|
}
|
||||||
|
|
||||||
// ErrorEncrypterExtracter defines a function signature that extracts an
|
// ErrorEncrypterExtracter defines a function signature that extracts an
|
||||||
// ErrorEncrypter from an sphinx OnionPacket.
|
// ErrorEncrypter from an sphinx OnionPacket.
|
||||||
type ErrorEncrypterExtracter func(*btcec.PublicKey) (ErrorEncrypter,
|
type ErrorEncrypterExtracter func(*btcec.PublicKey) (ErrorEncrypter,
|
||||||
|
@ -1793,8 +1793,20 @@ func (l *channelLink) handleDownstreamPkt(pkt *htlcPacket) {
|
|||||||
htlc.ID = pkt.incomingHTLCID
|
htlc.ID = pkt.incomingHTLCID
|
||||||
|
|
||||||
// We send the HTLC message to the peer which initially created
|
// We send the HTLC message to the peer which initially created
|
||||||
// the HTLC.
|
// the HTLC. If the incoming blinding point is non-nil, we
|
||||||
l.cfg.Peer.SendMessage(false, htlc)
|
// know that we are a relaying node in a blinded path.
|
||||||
|
// Otherwise, we're either an introduction node or not part of
|
||||||
|
// a blinded path at all.
|
||||||
|
if err := l.sendIncomingHTLCFailureMsg(
|
||||||
|
htlc.ID,
|
||||||
|
pkt.obfuscator,
|
||||||
|
htlc.Reason,
|
||||||
|
); err != nil {
|
||||||
|
l.log.Errorf("unable to send HTLC failure: %v",
|
||||||
|
err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// If the packet does not have a link failure set, it failed
|
// If the packet does not have a link failure set, it failed
|
||||||
// further down the route so we notify a forwarding failure.
|
// further down the route so we notify a forwarding failure.
|
||||||
@ -3720,11 +3732,14 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l.cfg.Peer.SendMessage(false, &lnwire.UpdateFailHTLC{
|
// Send the appropriate failure message depending on whether we're
|
||||||
ChanID: l.ChanID(),
|
// in a blinded route or not.
|
||||||
ID: pd.HtlcIndex,
|
if err := l.sendIncomingHTLCFailureMsg(
|
||||||
Reason: reason,
|
pd.HtlcIndex, e, reason,
|
||||||
})
|
); err != nil {
|
||||||
|
l.log.Errorf("unable to send HTLC failure: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Notify a link failure on our incoming link. Outgoing htlc information
|
// Notify a link failure on our incoming link. Outgoing htlc information
|
||||||
// is not available at this point, because we have not decrypted the
|
// is not available at this point, because we have not decrypted the
|
||||||
@ -3753,6 +3768,95 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendPeerHTLCFailure handles sending a HTLC failure message back to the
|
||||||
|
// peer from which the HTLC was received. This function is primarily used to
|
||||||
|
// handle the special requirements of route blinding, specifically:
|
||||||
|
// - Forwarding nodes must switch out any errors with MalformedFailHTLC
|
||||||
|
// - Introduction nodes should return regular HTLC failure messages.
|
||||||
|
//
|
||||||
|
// It accepts the original opaque failure, which will be used in the case
|
||||||
|
// that we're not part of a blinded route and an error encrypter that'll be
|
||||||
|
// used if we are the introduction node and need to present an error as if
|
||||||
|
// we're the failing party.
|
||||||
|
//
|
||||||
|
// Note: this function does not yet handle special error cases for receiving
|
||||||
|
// nodes in blinded paths, as LND does not support blinded receives.
|
||||||
|
func (l *channelLink) sendIncomingHTLCFailureMsg(htlcIndex uint64,
|
||||||
|
e hop.ErrorEncrypter,
|
||||||
|
originalFailure lnwire.OpaqueReason) error {
|
||||||
|
|
||||||
|
var msg lnwire.Message
|
||||||
|
switch {
|
||||||
|
// Our circuit's error encrypter will be nil if this was a locally
|
||||||
|
// initiated payment. We can only hit a blinded error for a locally
|
||||||
|
// initiated payment if we allow ourselves to be picked as the
|
||||||
|
// introduction node for our own payments and in that case we
|
||||||
|
// shouldn't reach this code. To prevent the HTLC getting stuck,
|
||||||
|
// we fail it back and log an error.
|
||||||
|
// code.
|
||||||
|
case e == nil:
|
||||||
|
msg = &lnwire.UpdateFailHTLC{
|
||||||
|
ChanID: l.ChanID(),
|
||||||
|
ID: htlcIndex,
|
||||||
|
Reason: originalFailure,
|
||||||
|
}
|
||||||
|
|
||||||
|
l.log.Errorf("Unexpected blinded failure when "+
|
||||||
|
"we are the sending node, incoming htlc: %v(%v)",
|
||||||
|
l.ShortChanID(), htlcIndex)
|
||||||
|
|
||||||
|
// For cleartext hops (ie, non-blinded/normal) we don't need any
|
||||||
|
// transformation on the error message and can just send the original.
|
||||||
|
case !e.Type().IsBlinded():
|
||||||
|
msg = &lnwire.UpdateFailHTLC{
|
||||||
|
ChanID: l.ChanID(),
|
||||||
|
ID: htlcIndex,
|
||||||
|
Reason: originalFailure,
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we're the introduction node, we need to convert the error to
|
||||||
|
// a UpdateFailHTLC.
|
||||||
|
case e.Type() == hop.EncrypterTypeIntroduction:
|
||||||
|
l.log.Debugf("Introduction blinded node switching out failure "+
|
||||||
|
"error: %v", htlcIndex)
|
||||||
|
|
||||||
|
// The specification does not require that we set the onion
|
||||||
|
// blob.
|
||||||
|
failureMsg := lnwire.NewInvalidBlinding(nil)
|
||||||
|
reason, err := e.EncryptFirstHop(failureMsg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = &lnwire.UpdateFailHTLC{
|
||||||
|
ChanID: l.ChanID(),
|
||||||
|
ID: htlcIndex,
|
||||||
|
Reason: reason,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are a relaying node, we need to switch out any error that
|
||||||
|
// we've received to a malformed HTLC error.
|
||||||
|
case e.Type() == hop.EncrypterTypeRelaying:
|
||||||
|
l.log.Debugf("Relaying blinded node switching out malformed "+
|
||||||
|
"error: %v", htlcIndex)
|
||||||
|
|
||||||
|
msg = &lnwire.UpdateFailMalformedHTLC{
|
||||||
|
ChanID: l.ChanID(),
|
||||||
|
ID: htlcIndex,
|
||||||
|
FailureCode: lnwire.CodeInvalidBlinding,
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected encrypter: %d", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := l.cfg.Peer.SendMessage(false, msg); err != nil {
|
||||||
|
l.log.Warnf("Send update fail failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// sendMalformedHTLCError helper function which sends the malformed HTLC update
|
// sendMalformedHTLCError helper function which sends the malformed HTLC update
|
||||||
// to the payment sender.
|
// to the payment sender.
|
||||||
func (l *channelLink) sendMalformedHTLCError(htlcIndex uint64,
|
func (l *channelLink) sendMalformedHTLCError(htlcIndex uint64,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user