mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-05-30 01:30:11 +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
|
||||
)
|
||||
|
||||
// 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
|
||||
// ErrorEncrypter from an sphinx OnionPacket.
|
||||
type ErrorEncrypterExtracter func(*btcec.PublicKey) (ErrorEncrypter,
|
||||
|
@ -1793,8 +1793,20 @@ func (l *channelLink) handleDownstreamPkt(pkt *htlcPacket) {
|
||||
htlc.ID = pkt.incomingHTLCID
|
||||
|
||||
// We send the HTLC message to the peer which initially created
|
||||
// the HTLC.
|
||||
l.cfg.Peer.SendMessage(false, htlc)
|
||||
// the HTLC. If the incoming blinding point is non-nil, we
|
||||
// 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
|
||||
// further down the route so we notify a forwarding failure.
|
||||
@ -3720,11 +3732,14 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor,
|
||||
return
|
||||
}
|
||||
|
||||
l.cfg.Peer.SendMessage(false, &lnwire.UpdateFailHTLC{
|
||||
ChanID: l.ChanID(),
|
||||
ID: pd.HtlcIndex,
|
||||
Reason: reason,
|
||||
})
|
||||
// Send the appropriate failure message depending on whether we're
|
||||
// in a blinded route or not.
|
||||
if err := l.sendIncomingHTLCFailureMsg(
|
||||
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
|
||||
// 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
|
||||
// to the payment sender.
|
||||
func (l *channelLink) sendMalformedHTLCError(htlcIndex uint64,
|
||||
|
Loading…
x
Reference in New Issue
Block a user