htlcswitch: add processRemoteUpdateAddHTLC
This commit is contained in:
1 file changed
+81
-67
+81
-67
@@ -1920,77 +1920,12 @@ func (l *channelLink) handleUpstreamMsg(ctx context.Context,
|
|||||||
|
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case *lnwire.UpdateAddHTLC:
|
case *lnwire.UpdateAddHTLC:
|
||||||
if l.IsFlushing(Incoming) {
|
err := l.processRemoteUpdateAddHTLC(msg)
|
||||||
// This is forbidden by the protocol specification.
|
|
||||||
// The best chance we have to deal with this is to drop
|
|
||||||
// the connection. This should roll back the channel
|
|
||||||
// state to the last CommitSig. If the remote has
|
|
||||||
// already sent a CommitSig we haven't received yet,
|
|
||||||
// channel state will be re-synchronized with a
|
|
||||||
// ChannelReestablish message upon reconnection and the
|
|
||||||
// protocol state that caused us to flush the link will
|
|
||||||
// be rolled back. In the event that there was some
|
|
||||||
// non-deterministic behavior in the remote that caused
|
|
||||||
// them to violate the protocol, we have a decent shot
|
|
||||||
// at correcting it this way, since reconnecting will
|
|
||||||
// put us in the cleanest possible state to try again.
|
|
||||||
//
|
|
||||||
// In addition to the above, it is possible for us to
|
|
||||||
// hit this case in situations where we improperly
|
|
||||||
// handle message ordering due to concurrency choices.
|
|
||||||
// An issue has been filed to address this here:
|
|
||||||
// https://github.com/lightningnetwork/lnd/issues/8393
|
|
||||||
l.failf(
|
|
||||||
LinkFailureError{
|
|
||||||
code: ErrInvalidUpdate,
|
|
||||||
FailureAction: LinkFailureDisconnect,
|
|
||||||
PermanentFailure: false,
|
|
||||||
Warning: true,
|
|
||||||
},
|
|
||||||
"received add while link is flushing",
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disallow htlcs with blinding points set if we haven't
|
|
||||||
// enabled the feature. This saves us from having to process
|
|
||||||
// the onion at all, but will only catch blinded payments
|
|
||||||
// where we are a relaying node (as the blinding point will
|
|
||||||
// be in the payload when we're the introduction node).
|
|
||||||
if msg.BlindingPoint.IsSome() && l.cfg.DisallowRouteBlinding {
|
|
||||||
l.failf(LinkFailureError{code: ErrInvalidUpdate},
|
|
||||||
"blinding point included when route blinding "+
|
|
||||||
"is disabled")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have to check the limit here rather than later in the
|
|
||||||
// switch because the counterparty can keep sending HTLC's
|
|
||||||
// without sending a revoke. This would mean that the switch
|
|
||||||
// check would only occur later.
|
|
||||||
if l.isOverexposedWithHtlc(msg, true) {
|
|
||||||
l.failf(LinkFailureError{code: ErrInternalError},
|
|
||||||
"peer sent us an HTLC that exceeded our max "+
|
|
||||||
"fee exposure")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// We just received an add request from an upstream peer, so we
|
|
||||||
// add it to our state machine, then add the HTLC to our
|
|
||||||
// "settle" list in the event that we know the preimage.
|
|
||||||
index, err := l.channel.ReceiveHTLC(msg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.failf(LinkFailureError{code: ErrInvalidUpdate},
|
l.log.Errorf("failed to process remote ADD: %v", err)
|
||||||
"unable to handle upstream add HTLC: %v", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l.log.Tracef("receive upstream htlc with payment hash(%x), "+
|
|
||||||
"assigning index: %v", msg.PaymentHash[:], index)
|
|
||||||
|
|
||||||
case *lnwire.UpdateFulfillHTLC:
|
case *lnwire.UpdateFulfillHTLC:
|
||||||
pre := msg.PaymentPreimage
|
pre := msg.PaymentPreimage
|
||||||
idx := msg.ID
|
idx := msg.ID
|
||||||
@@ -4643,3 +4578,82 @@ func (l *channelLink) resumeLink(ctx context.Context) error {
|
|||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processRemoteUpdateAddHTLC takes an `UpdateAddHTLC` msg sent from the remote
|
||||||
|
// and processes it.
|
||||||
|
func (l *channelLink) processRemoteUpdateAddHTLC(
|
||||||
|
msg *lnwire.UpdateAddHTLC) error {
|
||||||
|
|
||||||
|
if l.IsFlushing(Incoming) {
|
||||||
|
// This is forbidden by the protocol specification. The best
|
||||||
|
// chance we have to deal with this is to drop the connection.
|
||||||
|
// This should roll back the channel state to the last
|
||||||
|
// CommitSig. If the remote has already sent a CommitSig we
|
||||||
|
// haven't received yet, channel state will be re-synchronized
|
||||||
|
// with a ChannelReestablish message upon reconnection and the
|
||||||
|
// protocol state that caused us to flush the link will be
|
||||||
|
// rolled back. In the event that there was some
|
||||||
|
// non-deterministic behavior in the remote that caused them to
|
||||||
|
// violate the protocol, we have a decent shot at correcting it
|
||||||
|
// this way, since reconnecting will put us in the cleanest
|
||||||
|
// possible state to try again.
|
||||||
|
//
|
||||||
|
// In addition to the above, it is possible for us to hit this
|
||||||
|
// case in situations where we improperly handle message
|
||||||
|
// ordering due to concurrency choices. An issue has been filed
|
||||||
|
// to address this here:
|
||||||
|
// https://github.com/lightningnetwork/lnd/issues/8393
|
||||||
|
err := errors.New("received add while link is flushing")
|
||||||
|
l.failf(
|
||||||
|
LinkFailureError{
|
||||||
|
code: ErrInvalidUpdate,
|
||||||
|
FailureAction: LinkFailureDisconnect,
|
||||||
|
PermanentFailure: false,
|
||||||
|
Warning: true,
|
||||||
|
}, err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallow htlcs with blinding points set if we haven't enabled the
|
||||||
|
// feature. This saves us from having to process the onion at all, but
|
||||||
|
// will only catch blinded payments where we are a relaying node (as the
|
||||||
|
// blinding point will be in the payload when we're the introduction
|
||||||
|
// node).
|
||||||
|
if msg.BlindingPoint.IsSome() && l.cfg.DisallowRouteBlinding {
|
||||||
|
err := errors.New("blinding point included when route " +
|
||||||
|
"blinding is disabled")
|
||||||
|
|
||||||
|
l.failf(LinkFailureError{code: ErrInvalidUpdate}, err.Error())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to check the limit here rather than later in the switch
|
||||||
|
// because the counterparty can keep sending HTLC's without sending a
|
||||||
|
// revoke. This would mean that the switch check would only occur later.
|
||||||
|
if l.isOverexposedWithHtlc(msg, true) {
|
||||||
|
err := errors.New("peer sent us an HTLC that exceeded our " +
|
||||||
|
"max fee exposure")
|
||||||
|
l.failf(LinkFailureError{code: ErrInternalError}, err.Error())
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We just received an add request from an upstream peer, so we add it
|
||||||
|
// to our state machine, then add the HTLC to our "settle" list in the
|
||||||
|
// event that we know the preimage.
|
||||||
|
index, err := l.channel.ReceiveHTLC(msg)
|
||||||
|
if err != nil {
|
||||||
|
l.failf(LinkFailureError{code: ErrInvalidUpdate},
|
||||||
|
"unable to handle upstream add HTLC: %v", err)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
l.log.Tracef("receive upstream htlc with payment hash(%x), "+
|
||||||
|
"assigning index: %v", msg.PaymentHash[:], index)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in new issue
Block a user