lnwire+htlcswitch: minor grammatical, formatting fixes after error PR

This commit is contained in:
Olaoluwa Osuntokun 2017-07-14 20:08:29 -07:00
parent 79b8d26b1a
commit a04fa76a4c
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
8 changed files with 265 additions and 203 deletions

@ -20,7 +20,7 @@ func (k *circuitKey) String() string {
} }
// paymentCircuit is used by the htlc switch subsystem to determine the // paymentCircuit is used by the htlc switch subsystem to determine the
// fowrards/backwards path for the settle/fail HTLC messages. A payment circuit // forwards/backwards path for the settle/fail HTLC messages. A payment circuit
// will be created once a channel link forwards the htlc add request and // will be created once a channel link forwards the htlc add request and
// removed when we receive settle/fail htlc message. // removed when we receive settle/fail htlc message.
type paymentCircuit struct { type paymentCircuit struct {
@ -38,7 +38,7 @@ type paymentCircuit struct {
// request back. // request back.
Dest lnwire.ShortChannelID Dest lnwire.ShortChannelID
// Obfuscator is used to obfuscate the onion failure before sending it // Obfuscator is used to re-encrypt the onion failure before sending it
// back to the originator of the payment. // back to the originator of the payment.
Obfuscator Obfuscator Obfuscator Obfuscator

@ -7,22 +7,31 @@ import (
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
// Deobfuscator entity which is used to de-obfuscate the onion opaque reason and // Deobfuscator is an interface that is used to decrypt the onion encrypted
// extract failure. // failure reason an extra out a well formed error.
type Deobfuscator interface { type Deobfuscator interface {
// Deobfuscate function decodes the onion error failure. // Deobfuscate peels off each layer of onion encryption from the first
// hop, to the source of the error. A fully populated
// lnwire.FailureMessage is returned.
Deobfuscate(lnwire.OpaqueReason) (lnwire.FailureMessage, error) Deobfuscate(lnwire.OpaqueReason) (lnwire.FailureMessage, error)
} }
// Obfuscator entity which is used to do the initial and backward onion // Obfuscator is an interface that is used to encrypt HTLC related errors at
// failure obfuscation. // the source of the error, and also at each intermediate hop all the way back
// to the source of the payment.
type Obfuscator interface { type Obfuscator interface {
// InitialObfuscate is used to convert the failure into opaque // InitialObfuscate is used to convert the failure into opaque
// reason. // reason.
// InitialObfuscate transforms a concrete failure message into an
// encrypted opaque failure reason. This method will be used at the
// source that the error occurs. It differs from BackwardObfuscate
// slightly, in that it computes a proper MAC over the error.
InitialObfuscate(lnwire.FailureMessage) (lnwire.OpaqueReason, error) InitialObfuscate(lnwire.FailureMessage) (lnwire.OpaqueReason, error)
// BackwardObfuscate is used to make the processing over onion error // BackwardObfuscate wraps an already encrypted opaque reason error in
// when it moves backward to the htlc sender. // an additional layer of onion encryption. This process repeats until
// the error arrives at the source of the payment.
BackwardObfuscate(lnwire.OpaqueReason) lnwire.OpaqueReason BackwardObfuscate(lnwire.OpaqueReason) lnwire.OpaqueReason
} }
@ -31,35 +40,36 @@ type FailureObfuscator struct {
*sphinx.OnionObfuscator *sphinx.OnionObfuscator
} }
// InitialObfuscate is used by the failure sender to decode the failure and // InitialObfuscate transforms a concrete failure message into an encrypted
// make the initial failure obfuscation with addition of the failure data hmac. // opaque failure reason. This method will be used at the source that the error
// occurs. It differs from BackwardObfuscate slightly, in that it computes a
// proper MAC over the error.
// //
// NOTE: Part of the Obfuscator interface. // NOTE: Part of the Obfuscator interface.
func (o *FailureObfuscator) InitialObfuscate(failure lnwire.FailureMessage) ( func (o *FailureObfuscator) InitialObfuscate(failure lnwire.FailureMessage) (lnwire.OpaqueReason, error) {
lnwire.OpaqueReason, error) {
var b bytes.Buffer var b bytes.Buffer
if err := lnwire.EncodeFailure(&b, failure, 0); err != nil { if err := lnwire.EncodeFailure(&b, failure, 0); err != nil {
return nil, err return nil, err
} }
// Make the initial obfuscation with appending hmac. // We pass a true as the first parameter to indicate that a MAC should
// be added.
return o.OnionObfuscator.Obfuscate(true, b.Bytes()), nil return o.OnionObfuscator.Obfuscate(true, b.Bytes()), nil
} }
// BackwardObfuscate is used by the forwarding nodes in order to obfuscate the // BackwardObfuscate wraps an already encrypted opaque reason error in an
// already obfuscated onion failure blob with the stream which have been // additional layer of onion encryption. This process repeats until the error
// generated with our shared secret. The reason we re-encrypt the message on the // arrives at the source of the payment. We re-encrypt the message on the
// backwards path is to ensure that the error is computationally // backwards path to ensure that the error is indistinguishable from any other
// indistinguishable from any other error seen. // error seen.
// //
// NOTE: Part of the Obfuscator interface. // NOTE: Part of the Obfuscator interface.
func (o *FailureObfuscator) BackwardObfuscate( func (o *FailureObfuscator) BackwardObfuscate(reason lnwire.OpaqueReason) lnwire.OpaqueReason {
reason lnwire.OpaqueReason) lnwire.OpaqueReason {
return o.OnionObfuscator.Obfuscate(false, reason) return o.OnionObfuscator.Obfuscate(false, reason)
} }
// A compile time check to ensure FailureObfuscator implements the // A compile time check to ensure FailureObfuscator implements the Obfuscator
// Obfuscator interface. // interface.
var _ Obfuscator = (*FailureObfuscator)(nil) var _ Obfuscator = (*FailureObfuscator)(nil)
// FailureDeobfuscator wraps the sphinx data obfuscator and adds awareness of // FailureDeobfuscator wraps the sphinx data obfuscator and adds awareness of
@ -68,11 +78,13 @@ type FailureDeobfuscator struct {
*sphinx.OnionDeobfuscator *sphinx.OnionDeobfuscator
} }
// Deobfuscate decodes the obfuscated onion failure. // Deobfuscate peels off each layer of onion encryption from the first hop, to
// the source of the error. A fully populated lnwire.FailureMessage is
// returned.
// //
// NOTE: Part of the Obfuscator interface. // NOTE: Part of the Obfuscator interface.
func (o *FailureDeobfuscator) Deobfuscate(reason lnwire.OpaqueReason) (lnwire.FailureMessage, func (o *FailureDeobfuscator) Deobfuscate(reason lnwire.OpaqueReason) (lnwire.FailureMessage, error) {
error) {
_, failureData, err := o.OnionDeobfuscator.Deobfuscate(reason) _, failureData, err := o.OnionDeobfuscator.Deobfuscate(reason)
if err != nil { if err != nil {
return nil, err return nil, err

@ -191,10 +191,11 @@ func (p *OnionProcessor) DecodeHopIterator(r io.Reader, rHash []byte) (HopIterat
}, lnwire.CodeNone }, lnwire.CodeNone
} }
// DecodeOnionObfuscator takes the onion blob as input extract the shared secret // DecodeOnionObfuscator takes an io.Reader which should contain the onion
// and return the entity which is able to obfuscate failure data. // packet as original received by a forwarding node and creates an Obfuscator
func (p *OnionProcessor) DecodeOnionObfuscator(r io.Reader) (Obfuscator, // instance using the derived shared secret. In the case that en error occurs,
lnwire.FailCode) { // a lnwire failure code detailing the parsing failure will be returned.
func (p *OnionProcessor) DecodeOnionObfuscator(r io.Reader) (Obfuscator, lnwire.FailCode) {
onionPkt := &sphinx.OnionPacket{} onionPkt := &sphinx.OnionPacket{}
if err := onionPkt.Decode(r); err != nil { if err := onionPkt.Decode(r); err != nil {
return nil, lnwire.CodeTemporaryChannelFailure return nil, lnwire.CodeTemporaryChannelFailure

@ -83,17 +83,18 @@ type ChannelLinkConfig struct {
// contained in the forwarding blob within each HTLC. // contained in the forwarding blob within each HTLC.
Switch *Switch Switch *Switch
// DecodeHopIterator function is responsible for decoding htlc Sphinx onion // DecodeHopIterator function is responsible for decoding htlc Sphinx
// blob, and creating hop iterator which will give us next destination // onion blob, and creating hop iterator which will give us next
// of htlc. // destination of htlc.
DecodeHopIterator func(r io.Reader, rHash []byte) (HopIterator, lnwire.FailCode) DecodeHopIterator func(r io.Reader, rHash []byte) (HopIterator, lnwire.FailCode)
// DecodeOnionObfuscator function is responsible for decoding htlc Sphinx // DecodeOnionObfuscator function is responsible for decoding htlc
// onion blob, and creating onion failure obfuscator. // Sphinx onion blob, and creating onion failure obfuscator.
DecodeOnionObfuscator func(r io.Reader) (Obfuscator, lnwire.FailCode) DecodeOnionObfuscator func(r io.Reader) (Obfuscator, lnwire.FailCode)
// GetLastChannelUpdate retrieve the topology info about the channel in // GetLastChannelUpdate reterives the latest routing policy for this
// order to create the channel update. // particualr channel. This will be used to provide payment senders our
// laest policy when sending encrypted error messages.
GetLastChannelUpdate func() (*lnwire.ChannelUpdate, error) GetLastChannelUpdate func() (*lnwire.ChannelUpdate, error)
// Peer is a lightning network node with which we have the channel link // Peer is a lightning network node with which we have the channel link
@ -419,6 +420,9 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket) {
index, err := l.channel.AddHTLC(htlc) index, err := l.channel.AddHTLC(htlc)
if err != nil { if err != nil {
switch err { switch err {
// The channels spare bandwidth is fully allocated, so
// we'll put this HTLC into the overflow queue.
case lnwallet.ErrMaxHTLCNumber: case lnwallet.ErrMaxHTLCNumber:
log.Infof("Downstream htlc add update with "+ log.Infof("Downstream htlc add update with "+
"payment hash(%x) have been added to "+ "payment hash(%x) have been added to "+
@ -428,19 +432,26 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket) {
l.overflowQueue.consume(pkt) l.overflowQueue.consume(pkt)
return return
default:
// The HTLC was unable to be added to the state // The HTLC was unable to be added to the state
// machine, as a result, we'll signal the switch to // machine, as a result, we'll signal the switch to
// cancel the pending payment. // cancel the pending payment.
default:
var ( var (
isObfuscated bool isObfuscated bool
reason lnwire.OpaqueReason reason lnwire.OpaqueReason
) )
// We'll parse the sphinx packet enclosed so we
// can obtain the shared secret required to
// encrypt the error back to the source.
failure := lnwire.NewTemporaryChannelFailure(nil) failure := lnwire.NewTemporaryChannelFailure(nil)
onionReader := bytes.NewReader(htlc.OnionBlob[:]) onionReader := bytes.NewReader(htlc.OnionBlob[:])
obfuscator, failCode := l.cfg.DecodeOnionObfuscator(onionReader) obfuscator, failCode := l.cfg.DecodeOnionObfuscator(onionReader)
if failCode != lnwire.CodeNone {
switch {
// If we were unable to parse the onion blob,
// then we'll send an error back to the source.
case failCode != lnwire.CodeNone:
var b bytes.Buffer var b bytes.Buffer
err := lnwire.EncodeFailure(&b, failure, 0) err := lnwire.EncodeFailure(&b, failure, 0)
if err != nil { if err != nil {
@ -449,7 +460,10 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket) {
} }
reason = lnwire.OpaqueReason(b.Bytes()) reason = lnwire.OpaqueReason(b.Bytes())
isObfuscated = false isObfuscated = false
} else {
// Otherwise, we'll send back a proper failure
// message.
default:
reason, err = obfuscator.InitialObfuscate(failure) reason, err = obfuscator.InitialObfuscate(failure)
if err != nil { if err != nil {
log.Errorf("unable to obfuscate error: %v", err) log.Errorf("unable to obfuscate error: %v", err)
@ -458,13 +472,16 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket) {
isObfuscated = true isObfuscated = true
} }
go l.cfg.Switch.forward(newFailPacket( upddateFail := &lnwire.UpdateFailHTLC{
l.ShortChanID(),
&lnwire.UpdateFailHTLC{
Reason: reason, Reason: reason,
}, htlc.PaymentHash, htlc.Amount, isObfuscated, }
)) failPkt := newFailPacket(
l.ShortChanID(), upddateFail,
htlc.PaymentHash, htlc.Amount,
isObfuscated,
)
go l.cfg.Switch.forward(failPkt)
log.Infof("Unable to handle downstream add HTLC: %v", err) log.Infof("Unable to handle downstream add HTLC: %v", err)
return return
} }
@ -568,16 +585,18 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
// TODO(roasbeef): add preimage to DB in order to swipe // TODO(roasbeef): add preimage to DB in order to swipe
// repeated r-values // repeated r-values
// If remote side have been unable to parse the onion blob we have sent
// to it, than we should transform the malformed notification to the the
// usual htlc fail message.
case *lnwire.UpdateFailMalformedHTLC: case *lnwire.UpdateFailMalformedHTLC:
// 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.
idx := msg.ID idx := msg.ID
if err := l.channel.ReceiveFailHTLC(idx); err != nil { if err := l.channel.ReceiveFailHTLC(idx); err != nil {
l.fail("unable to handle upstream fail HTLC: %v", err) l.fail("unable to handle upstream fail HTLC: %v", err)
return return
} }
// Convert the failure type encoded within the HTLC fail
// message to the proper generic lnwire error code.
var failure lnwire.FailureMessage var failure lnwire.FailureMessage
switch msg.FailureCode { switch msg.FailureCode {
case lnwire.CodeInvalidOnionVersion: case lnwire.CodeInvalidOnionVersion:
@ -594,11 +613,14 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
OnionSHA256: msg.ShaOnionBlob, OnionSHA256: msg.ShaOnionBlob,
} }
default: default:
// TODO(roasbeef): fail channel here?
log.Errorf("unable to understand code of received " + log.Errorf("unable to understand code of received " +
"malformed error") "malformed error")
return return
} }
// With the error parsed, we'll convert the into it's opaque
// form.
var b bytes.Buffer var b bytes.Buffer
if err := lnwire.EncodeFailure(&b, failure, 0); err != nil { if err := lnwire.EncodeFailure(&b, failure, 0); err != nil {
log.Errorf("unable to encode malformed error: %v", err) log.Errorf("unable to encode malformed error: %v", err)
@ -943,7 +965,7 @@ func (l *channelLink) processLockedInHtlcs(
// An incoming HTLC add has been full-locked in. As a result we // An incoming HTLC add has been full-locked in. As a result we
// can no examine the forwarding details of the HTLC, and the // can no examine the forwarding details of the HTLC, and the
// HTLC itself ti decide if: we should forward it, cancel it, // HTLC itself to decide if: we should forward it, cancel it,
// or are able to settle it (and it adheres to our fee related // or are able to settle it (and it adheres to our fee related
// constraints). // constraints).
case lnwallet.Add: case lnwallet.Add:
@ -952,23 +974,26 @@ func (l *channelLink) processLockedInHtlcs(
onionBlob := l.clearedOnionBlobs[pd.Index] onionBlob := l.clearedOnionBlobs[pd.Index]
delete(l.clearedOnionBlobs, pd.Index) delete(l.clearedOnionBlobs, pd.Index)
// Retrieve onion obfuscator from onion blob in order to produce // Retrieve onion obfuscator from onion blob in order
// initial obfuscation of the onion failureCode. // to produce initial obfuscation of the onion
// failureCode.
onionReader := bytes.NewReader(onionBlob[:]) onionReader := bytes.NewReader(onionBlob[:])
obfuscator, failureCode := l.cfg.DecodeOnionObfuscator(onionReader) obfuscator, failureCode := l.cfg.DecodeOnionObfuscator(onionReader)
if failureCode != lnwire.CodeNone { if failureCode != lnwire.CodeNone {
log.Error("unable to decode onion obfuscator") // If we unable to process the onion blob than
// If we unable to process the onion blob than we should send // we should send the malformed htlc error to
// the malformed htlc error to payment sender. // payment sender.
l.sendMalformedHTLCError(pd.RHash, failureCode, onionBlob[:]) l.sendMalformedHTLCError(pd.RHash, failureCode, onionBlob[:])
needUpdate = true needUpdate = true
log.Error("unable to decode onion obfuscator")
continue continue
} }
// Before adding the new htlc to the state machine, // Before adding the new htlc to the state machine,
// parse the onion object in order to obtain the // parse the onion object in order to obtain the
// routing information with DecodeHopIterator function which // routing information with DecodeHopIterator function
// process the Sphinx packet. // which process the Sphinx packet.
// //
// We include the payment hash of the htlc as it's // We include the payment hash of the htlc as it's
// authenticated within the Sphinx packet itself as // authenticated within the Sphinx packet itself as
@ -979,11 +1004,13 @@ func (l *channelLink) processLockedInHtlcs(
onionReader = bytes.NewReader(onionBlob[:]) onionReader = bytes.NewReader(onionBlob[:])
chanIterator, failureCode := l.cfg.DecodeHopIterator(onionReader, pd.RHash[:]) chanIterator, failureCode := l.cfg.DecodeHopIterator(onionReader, pd.RHash[:])
if failureCode != lnwire.CodeNone { if failureCode != lnwire.CodeNone {
log.Error("unable to decode onion hop iterator") // If we unable to process the onion blob than
// If we unable to process the onion blob than we should send // we should send the malformed htlc error to
// the malformed htlc error to payment sender. // payment sender.
l.sendMalformedHTLCError(pd.RHash, failureCode, onionBlob[:]) l.sendMalformedHTLCError(pd.RHash, failureCode, onionBlob[:])
needUpdate = true needUpdate = true
log.Error("unable to decode onion hop iterator")
continue continue
} }
@ -1009,9 +1036,7 @@ func (l *channelLink) processLockedInHtlcs(
// the hop-payload included in the HTLC to // the hop-payload included in the HTLC to
// ensure that it was crafted correctly by the // ensure that it was crafted correctly by the
// sender and matches the HTLC we were // sender and matches the HTLC we were
// extended. Additionally, we'll ensure that // extended.
// our time-lock value has been computed
// correctly.
if !l.cfg.DebugHTLC && if !l.cfg.DebugHTLC &&
fwdInfo.AmountToForward != invoice.Terms.Value { fwdInfo.AmountToForward != invoice.Terms.Value {
@ -1026,6 +1051,9 @@ func (l *channelLink) processLockedInHtlcs(
needUpdate = true needUpdate = true
continue continue
} }
// We'll also ensure that our time-lock value
// has been computed correctly.
if !l.cfg.DebugHTLC && if !l.cfg.DebugHTLC &&
fwdInfo.OutgoingCTLV != l.cfg.FwrdingPolicy.TimeLockDelta { fwdInfo.OutgoingCTLV != l.cfg.FwrdingPolicy.TimeLockDelta {
@ -1096,6 +1124,10 @@ func (l *channelLink) processLockedInHtlcs(
pd.RHash[:], l.cfg.FwrdingPolicy.MinHTLC, pd.RHash[:], l.cfg.FwrdingPolicy.MinHTLC,
pd.Amount) pd.Amount)
// As part of the returned error, we'll
// send our latest routing policy so
// the sending node obtains the most up
// to date data.
var failure lnwire.FailureMessage var failure lnwire.FailureMessage
update, err := l.cfg.GetLastChannelUpdate() update, err := l.cfg.GetLastChannelUpdate()
if err != nil { if err != nil {
@ -1134,6 +1166,10 @@ func (l *channelLink) processLockedInHtlcs(
btcutil.Amount(pd.Amount-fwdInfo.AmountToForward), btcutil.Amount(pd.Amount-fwdInfo.AmountToForward),
btcutil.Amount(expectedFee)) btcutil.Amount(expectedFee))
// As part of the returned error, we'll
// send our latest routing policy so
// the sending node obtains the most up
// to date data.
var failure lnwire.FailureMessage var failure lnwire.FailureMessage
update, err := l.cfg.GetLastChannelUpdate() update, err := l.cfg.GetLastChannelUpdate()
if err != nil { if err != nil {
@ -1163,6 +1199,9 @@ func (l *channelLink) processLockedInHtlcs(
pd.RHash[:], pd.Timeout-timeDelta, pd.RHash[:], pd.Timeout-timeDelta,
fwdInfo.OutgoingCTLV) fwdInfo.OutgoingCTLV)
// Grab the latest routing policy so
// the sending node is up to date with
// our current policy.
update, err := l.cfg.GetLastChannelUpdate() update, err := l.cfg.GetLastChannelUpdate()
if err != nil { if err != nil {
l.fail("unable to create channel update "+ l.fail("unable to create channel update "+
@ -1211,7 +1250,7 @@ func (l *channelLink) processLockedInHtlcs(
if needUpdate { if needUpdate {
// With all the settle/cancel updates added to the local and // With all the settle/cancel updates added to the local and
// remote htlc logs, initiate a state transition by updating // remote HTLC logs, initiate a state transition by updating
// the remote commitment chain. // the remote commitment chain.
if err := l.updateCommitTx(); err != nil { if err := l.updateCommitTx(); err != nil {
l.fail("unable to update commitment: %v", err) l.fail("unable to update commitment: %v", err)
@ -1222,8 +1261,8 @@ func (l *channelLink) processLockedInHtlcs(
return packetsToForward return packetsToForward
} }
// sendHTLCError functions cancels htlc and send cancel message back to the // sendHTLCError functions cancels HTLC and send cancel message back to the
// peer from which htlc was received. // peer from which HTLC was received.
func (l *channelLink) sendHTLCError(rHash [32]byte, failure lnwire.FailureMessage, func (l *channelLink) sendHTLCError(rHash [32]byte, failure lnwire.FailureMessage,
obfuscator Obfuscator) { obfuscator Obfuscator) {
reason, err := obfuscator.InitialObfuscate(failure) reason, err := obfuscator.InitialObfuscate(failure)
@ -1245,7 +1284,7 @@ func (l *channelLink) sendHTLCError(rHash [32]byte, failure lnwire.FailureMessag
}) })
} }
// 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(rHash [32]byte, code lnwire.FailCode, func (l *channelLink) sendMalformedHTLCError(rHash [32]byte, code lnwire.FailCode,
onionBlob []byte) { onionBlob []byte) {
@ -1263,8 +1302,8 @@ func (l *channelLink) sendMalformedHTLCError(rHash [32]byte, code lnwire.FailCod
}) })
} }
// fail helper function which is used to encapsulate the action neccessary // fail helper function which is used to encapsulate the action necessary for
// for proper disconnect. // proper disconnect.
func (l *channelLink) fail(format string, a ...interface{}) { func (l *channelLink) fail(format string, a ...interface{}) {
reason := errors.Errorf(format, a...) reason := errors.Errorf(format, a...)
log.Error(reason) log.Error(reason)

@ -35,20 +35,19 @@ type htlcPacket struct {
// htlc lnwire message type of which depends on switch request type. // htlc lnwire message type of which depends on switch request type.
htlc lnwire.Message htlc lnwire.Message
// obfuscator is entity which is needed to make the obfuscation of the // obfuscator contains the necessary state to allow the switch to wrap
// onion failure, it is carried inside the packet from channel // any forwarded errors in an additional layer of encryption.
// link to the switch because we have to create onion error inside the //
// switch to, but we unable to restore obfuscator from the onion, because // TODO(andrew.shvv) revisit after refactoring the way of returning
// on stage of forwarding onion inside payment belongs to the remote node. // errors inside the htlcswitch packet.
// TODO(andrew.shvv) revisit after refactoring the way of returning errors
// inside the htlcswitch packet.
obfuscator Obfuscator obfuscator Obfuscator
// isObfuscated is used in case if switch sent the packet to the link, // isObfuscated is set to true if an error occurs as soon as the switch
// but error have occurred locally, in this case we shouldn't obfuscate // forwards a packet to the link. If so, and this is an error packet,
// it again. // then this allows the switch to avoid doubly encrypting the error.
// TODO(andrew.shvv) revisit after refactoring the way of returning errors //
// inside the htlcswitch packet. // TODO(andrew.shvv) revisit after refactoring the way of returning
// errors inside the htlcswitch packet.
isObfuscated bool isObfuscated bool
} }

@ -304,23 +304,27 @@ func (s *Switch) handleLocalDispatch(payment *pendingPayment, packet *htlcPacket
payment.preimage <- htlc.PaymentPreimage payment.preimage <- htlc.PaymentPreimage
s.removePendingPayment(payment.amount, payment.paymentHash) s.removePendingPayment(payment.amount, payment.paymentHash)
// We've just received a fail update which means we can finalize // We've just received a fail update which means we can finalize the
// the user payment and return fail response. // user payment and return fail response.
case *lnwire.UpdateFailHTLC: case *lnwire.UpdateFailHTLC:
// Retrieving the fail code from byte representation of error.
var userErr error var userErr error
// We'll attempt to fully decrypt the onion encrypted error. If
// we're unable to then we'll bail early.
failure, err := payment.deobfuscator.Deobfuscate(htlc.Reason) failure, err := payment.deobfuscator.Deobfuscate(htlc.Reason)
if err != nil { if err != nil {
userErr = errors.Errorf("unable to de-obfuscate "+ userErr = errors.Errorf("unable to de-obfuscate "+
"onion failure, htlc with hash(%v): %v", payment.paymentHash[:], "onion failure, htlc with hash(%v): %v",
err) payment.paymentHash[:], err)
log.Error(userErr) log.Error(userErr)
} else { } else {
// Process payment failure by updating the lightning network // Process payment failure by updating the lightning
// topology by using router subsystem handler. // network topology by using router subsystem handler.
var update *lnwire.ChannelUpdate var update *lnwire.ChannelUpdate
// Only a few error message actually contain a channel
// update message, so we'll filter out for those that
// do.
switch failure := failure.(type) { switch failure := failure.(type) {
case *lnwire.FailTemporaryChannelFailure: case *lnwire.FailTemporaryChannelFailure:
update = failure.Update update = failure.Update
@ -336,10 +340,21 @@ func (s *Switch) handleLocalDispatch(payment *pendingPayment, packet *htlcPacket
update = &failure.Update update = &failure.Update
} }
// If we've been sent an error that includes an update,
// then we'll apply it to the local graph.
//
// TODO(roasbeef): instead, make all onion errors the
// error interface, and handle this within the router.
// Will allow us more flexibility w.r.t how we handle
// the error.
if update != nil { if update != nil {
log.Info("Received payment failure(%v), applying lightning "+ log.Info("Received payment failure(%v), "+
"network topology update", failure.Code()) "applying lightning network topology update",
s.cfg.UpdateTopology(update) failure.Code())
if err := s.cfg.UpdateTopology(update); err != nil {
log.Errorf("unable to update topology: %v", err)
}
} }
userErr = errors.New(failure.Code()) userErr = errors.New(failure.Code())
@ -611,15 +626,23 @@ func (s *Switch) htlcForwarder() {
for { for {
select { select {
// A local close request has arrived, we'll forward this to the
// relevant link (if it exists) so the channel can be
// cooperatively closed (if possible).
case req := <-s.chanCloseRequests: case req := <-s.chanCloseRequests:
s.handleChanelClose(req) s.handleChanelClose(req)
// A new packet has arrived for forwarding, we'll interpret the
// packet concretely, then either forward it along, or
// interpret a return packet to a locally initialized one.
case cmd := <-s.htlcPlex: case cmd := <-s.htlcPlex:
var ( var (
paymentHash lnwallet.PaymentHash paymentHash lnwallet.PaymentHash
amount btcutil.Amount amount btcutil.Amount
) )
// Only three types of message should be forwarded:
// add, fails, and settles. Anything else is an error.
switch m := cmd.pkt.htlc.(type) { switch m := cmd.pkt.htlc.(type) {
case *lnwire.UpdateAddHTLC: case *lnwire.UpdateAddHTLC:
paymentHash = m.PaymentHash paymentHash = m.PaymentHash
@ -632,6 +655,12 @@ func (s *Switch) htlcForwarder() {
return return
} }
// If we can locate this packet in our local records,
// then this means a local sub-system initiated it.
// Otherwise, this is just a packet to be forwarded, so
// we'll treat it as so.
//
// TODO(roasbeef): can fast path this
payment, err := s.findPayment(amount, paymentHash) payment, err := s.findPayment(amount, paymentHash)
if err != nil { if err != nil {
cmd.err <- s.handlePacketForward(cmd.pkt) cmd.err <- s.handlePacketForward(cmd.pkt)

@ -10,34 +10,36 @@ import (
"github.com/roasbeef/btcutil" "github.com/roasbeef/btcutil"
) )
// FailureMessage represent the onion failure object which is able to identify itself // FailureMessage represents the onion failure object identified by its unique
// by returning the unique failure code. // failure code.
type FailureMessage interface { type FailureMessage interface {
Code() FailCode Code() FailCode
} }
// failureMessageLength is the size of the failure message plus the size // failureMessageLength is the size of the failure message plus the size of
// of padding. FailureMessage message always should be equals to this size. // padding. The FailureMessage message should always be EXACLTY this size.
const failureMessageLength = 128 const failureMessageLength = 128
const ( const (
// FlagBadOnion error flag denotes unparsable onion, encrypted by // FlagBadOnion error flag describes an unparseable, encrypted by
// previous node. // previous node.
FlagBadOnion FailCode = 0x8000 FlagBadOnion FailCode = 0x8000
// FlagPerm error flag denotes permanent failure. // FlagPerm error flag indicates a permanent failure.
FlagPerm FailCode = 0x4000 FlagPerm FailCode = 0x4000
// FlagNode error flag denotes node failure. // FlagNode error flag indicates anode failure.
FlagNode FailCode = 0x2000 FlagNode FailCode = 0x2000
// FlagUpdate error flag denotes new channel update enclosed. // FlagUpdate error flag indicates a new channel update is enclosed
// within the error.
FlagUpdate FailCode = 0x1000 FlagUpdate FailCode = 0x1000
) )
// FailCode specifies the precise reason that an upstream HTLC was cancelled. // FailCode specifies the precise reason that an upstream HTLC was cancelled.
// Each UpdateFailHTLC message carries a FailCode which is to be passed back // Each UpdateFailHTLC message carries a FailCode which is to be passed
// unaltered to the source of the HTLC within the route. // backwards, encrypted at each step back to the source of the HTLC within the
// route.
type FailCode uint16 type FailCode uint16
// The currently defined onion failure types within this current version of the // The currently defined onion failure types within this current version of the
@ -67,7 +69,7 @@ const (
CodeFinalIncorrectHtlcAmount FailCode = 19 CodeFinalIncorrectHtlcAmount FailCode = 19
) )
// String returns string representation of the failure code. // String returns the string representation of the failure code.
func (c FailCode) String() string { func (c FailCode) String() string {
switch c { switch c {
case CodeInvalidRealm: case CodeInvalidRealm:
@ -140,7 +142,7 @@ func (c FailCode) String() string {
// FailInvalidRealm is returned if the realm byte is unknown. // FailInvalidRealm is returned if the realm byte is unknown.
// //
// NOTE: might be returned by any node. // NOTE: May be returned by any node in the payment route.
type FailInvalidRealm struct{} type FailInvalidRealm struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -153,7 +155,7 @@ func (f FailInvalidRealm) Code() FailCode {
// FailTemporaryNodeFailure is returned if an otherwise unspecified transient // FailTemporaryNodeFailure is returned if an otherwise unspecified transient
// error occurs for the entire node. // error occurs for the entire node.
// //
// NOTE: might be returned by any node. // NOTE: May be returned by any node in the payment route.
type FailTemporaryNodeFailure struct{} type FailTemporaryNodeFailure struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -165,7 +167,7 @@ func (f FailTemporaryNodeFailure) Code() FailCode {
// FailPermanentNodeFailure is returned if an otherwise unspecified permanent // FailPermanentNodeFailure is returned if an otherwise unspecified permanent
// error occurs for the entire node. // error occurs for the entire node.
// //
// NOTE: might be returned by any node. // NOTE: May be returned by any node in the payment route.
type FailPermanentNodeFailure struct{} type FailPermanentNodeFailure struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -179,7 +181,7 @@ func (f FailPermanentNodeFailure) Code() FailCode {
// advertised in its node_announcement features which were not present in the // advertised in its node_announcement features which were not present in the
// onion. // onion.
// //
// NOTE: might be returned by any node. // NOTE: May be returned by any node in the payment route.
type FailRequiredNodeFeatureMissing struct{} type FailRequiredNodeFeatureMissing struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -189,10 +191,10 @@ func (f FailRequiredNodeFeatureMissing) Code() FailCode {
return CodeRequiredNodeFeatureMissing return CodeRequiredNodeFeatureMissing
} }
// FailPermanentChannelFailure is return if an otherwise unspecified // FailPermanentChannelFailure is return if an otherwise unspecified permanent
// permanent error occurs for the outgoing channel (eg. channel (recently). // error occurs for the outgoing channel (eg. channel (recently).
// //
// NOTE: might be return by forwarding node only. // NOTE: May be returned by any node in the payment route.
type FailPermanentChannelFailure struct{} type FailPermanentChannelFailure struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -202,11 +204,11 @@ func (f FailPermanentChannelFailure) Code() FailCode {
return CodePermanentChannelFailure return CodePermanentChannelFailure
} }
// FailRequiredChannelFeatureMissing is return if the outgoing channel has // FailRequiredChannelFeatureMissing is returned if the outgoing channel has a
// requirement advertised in its channel announcement features which were not // requirement advertised in its channel announcement features which were not
// present in the onion. // present in the onion.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailRequiredChannelFeatureMissing struct{} type FailRequiredChannelFeatureMissing struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -219,7 +221,7 @@ func (f FailRequiredChannelFeatureMissing) Code() FailCode {
// FailUnknownNextPeer is returned if the next peer specified by the onion is // FailUnknownNextPeer is returned if the next peer specified by the onion is
// not known. // not known.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailUnknownNextPeer struct{} type FailUnknownNextPeer struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -229,12 +231,12 @@ func (f FailUnknownNextPeer) Code() FailCode {
return CodeUnknownNextPeer return CodeUnknownNextPeer
} }
// FailUnknownPaymentHash is returned If the payment hash has already been paid, // FailUnknownPaymentHash is returned If the payment hash has already been
// the final node MAY treat the payment hash as unknown, or may succeed in // paid, the final node MAY treat the payment hash as unknown, or may succeed
// accepting the HTLC. If the payment hash is unknown, the final node MUST fail // in accepting the HTLC. If the payment hash is unknown, the final node MUST
// the HTLC. // fail the HTLC.
// //
// NOTE: might be returned by final node only. // NOTE: May only be returned by the final node in the path.
type FailUnknownPaymentHash struct{} type FailUnknownPaymentHash struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -250,7 +252,7 @@ func (f FailUnknownPaymentHash) Code() FailCode {
// This allows the sender to reduce information leakage by altering the amount, // This allows the sender to reduce information leakage by altering the amount,
// without allowing accidental gross overpayment. // without allowing accidental gross overpayment.
// //
// NOTE: might be returned by final node only. // NOTE: May only be returned by the final node in the path.
type FailIncorrectPaymentAmount struct{} type FailIncorrectPaymentAmount struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -263,7 +265,7 @@ func (f FailIncorrectPaymentAmount) Code() FailCode {
// FailFinalExpiryTooSoon is returned if the cltv_expiry is too low, the final // FailFinalExpiryTooSoon is returned if the cltv_expiry is too low, the final
// node MUST fail the HTLC. // node MUST fail the HTLC.
// //
// NOTE: might be returned by final node only. // NOTE: May only be returned by the final node in the path.
type FailFinalExpiryTooSoon struct{} type FailFinalExpiryTooSoon struct{}
// Code returns the failure unique code. // Code returns the failure unique code.
@ -275,7 +277,7 @@ func (f FailFinalExpiryTooSoon) Code() FailCode {
// FailInvalidOnionVersion is returned if the onion version byte is unknown. // FailInvalidOnionVersion is returned if the onion version byte is unknown.
// //
// NOTE: should be return by forwarding node only. // NOTE: May be returned only by intermediate nodes.
type FailInvalidOnionVersion struct { type FailInvalidOnionVersion struct {
// OnionSHA256 hash of the onion blob which haven't been proceeded. // OnionSHA256 hash of the onion blob which haven't been proceeded.
OnionSHA256 [sha256.Size]byte OnionSHA256 [sha256.Size]byte
@ -309,7 +311,7 @@ func (f *FailInvalidOnionVersion) Encode(w io.Writer, pver uint32) error {
// FailInvalidOnionHmac is return if the onion HMAC is incorrect. // FailInvalidOnionHmac is return if the onion HMAC is incorrect.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailInvalidOnionHmac struct { type FailInvalidOnionHmac struct {
// OnionSHA256 hash of the onion blob which haven't been proceeded. // OnionSHA256 hash of the onion blob which haven't been proceeded.
OnionSHA256 [sha256.Size]byte OnionSHA256 [sha256.Size]byte
@ -344,7 +346,7 @@ func (f *FailInvalidOnionHmac) Encode(w io.Writer, pver uint32) error {
// FailInvalidOnionKey is return if the ephemeral key in the onion is // FailInvalidOnionKey is return if the ephemeral key in the onion is
// unparsable. // unparsable.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailInvalidOnionKey struct { type FailInvalidOnionKey struct {
// OnionSHA256 hash of the onion blob which haven't been proceeded. // OnionSHA256 hash of the onion blob which haven't been proceeded.
OnionSHA256 [sha256.Size]byte OnionSHA256 [sha256.Size]byte
@ -376,16 +378,16 @@ func (f *FailInvalidOnionKey) Encode(w io.Writer, pver uint32) error {
return writeElement(w, f.OnionSHA256[:]) return writeElement(w, f.OnionSHA256[:])
} }
// FailTemporaryChannelFailure is if an otherwise unspecified transient // FailTemporaryChannelFailure is if an otherwise unspecified transient error
// error occurs for the outgoing channel (eg. channel capacity reached, // occurs for the outgoing channel (eg. channel capacity reached, too many
// too many in-flight htlc) // in-flight htlcs)
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailTemporaryChannelFailure struct { type FailTemporaryChannelFailure struct {
// Update is used to update information about state of the channel which // Update is used to update information about state of the channel
// caused the failure. // which caused the failure.
// //
// NOTE: Field is optional. // NOTE: This field is optional.
Update *ChannelUpdate Update *ChannelUpdate
} }
@ -439,11 +441,11 @@ func (f *FailTemporaryChannelFailure) Encode(w io.Writer, pver uint32) error {
return err return err
} }
// FailAmountBelowMinimum is returned if the HTLC does not reach the // FailAmountBelowMinimum is returned if the HTLC does not reach the current
// current minimum amount, we tell them the amount of the incoming HTLC // minimum amount, we tell them the amount of the incoming HTLC and the current
// and the current channel setting for the outgoing channel. // channel setting for the outgoing channel.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by the intermediate nodes in the path.
type FailAmountBelowMinimum struct { type FailAmountBelowMinimum struct {
// HtlcMsat is the wrong amount of the incoming HTLC. // HtlcMsat is the wrong amount of the incoming HTLC.
HtlcMsat btcutil.Amount HtlcMsat btcutil.Amount
@ -456,6 +458,7 @@ type FailAmountBelowMinimum struct {
// NewAmountBelowMinimum creates new instance of the FailAmountBelowMinimum. // NewAmountBelowMinimum creates new instance of the FailAmountBelowMinimum.
func NewAmountBelowMinimum(htlcMsat btcutil.Amount, func NewAmountBelowMinimum(htlcMsat btcutil.Amount,
update ChannelUpdate) *FailAmountBelowMinimum { update ChannelUpdate) *FailAmountBelowMinimum {
return &FailAmountBelowMinimum{ return &FailAmountBelowMinimum{
HtlcMsat: htlcMsat, HtlcMsat: htlcMsat,
Update: update, Update: update,
@ -477,8 +480,6 @@ func (f *FailAmountBelowMinimum) Decode(r io.Reader, pver uint32) error {
return err return err
} }
// At current moment length is not used but in future we may use it to
// differ versions of the update message.
var length uint16 var length uint16
if err := readElement(r, &length); err != nil { if err := readElement(r, &length); err != nil {
return err return err
@ -496,9 +497,6 @@ func (f *FailAmountBelowMinimum) Encode(w io.Writer, pver uint32) error {
return err return err
} }
// We write the length here as the size of the channel updates may differ in
// the future and at times additional information is coupled (appended to or
// prepended to the channel update itself) along with the channel update.
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver))) err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
if err != nil { if err != nil {
return err return err
@ -507,17 +505,17 @@ func (f *FailAmountBelowMinimum) Encode(w io.Writer, pver uint32) error {
return f.Update.Encode(w, pver) return f.Update.Encode(w, pver)
} }
// FailFeeInsufficient is returned if the HTLC does not pay sufficient // FailFeeInsufficient is returned if the HTLC does not pay sufficient fee, we
// fee, we tell them the amount of the incoming HTLC and the current // tell them the amount of the incoming HTLC and the current channel setting
// channel setting for the outgoing channel. // for the outgoing channel.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailFeeInsufficient struct { type FailFeeInsufficient struct {
// HtlcMsat is the wrong amount of the incoming HTLC. // HtlcMsat is the wrong amount of the incoming HTLC.
HtlcMsat btcutil.Amount HtlcMsat btcutil.Amount
// Update is used to update information about state of the channel which // Update is used to update information about state of the channel
// caused the failure. // which caused the failure.
Update ChannelUpdate Update ChannelUpdate
} }
@ -545,8 +543,6 @@ func (f *FailFeeInsufficient) Decode(r io.Reader, pver uint32) error {
return err return err
} }
// At current moment length is not used but in future we may use it to
// differ versions of the update message.
var length uint16 var length uint16
if err := readElement(r, &length); err != nil { if err := readElement(r, &length); err != nil {
return err return err
@ -564,9 +560,6 @@ func (f *FailFeeInsufficient) Encode(w io.Writer, pver uint32) error {
return err return err
} }
// We write the length here as the size of the channel updates may differ in
// the future and at times additional information is coupled (appended to or
// prepended to the channel update itself) along with the channel update.
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver))) err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
if err != nil { if err != nil {
return err return err
@ -575,24 +568,26 @@ func (f *FailFeeInsufficient) Encode(w io.Writer, pver uint32) error {
return f.Update.Encode(w, pver) return f.Update.Encode(w, pver)
} }
// FailIncorrectCltvExpiry is returned if outgoing cltv value does not // FailIncorrectCltvExpiry is returned if outgoing cltv value does not match
// match the update add htlc's cltv expiry minus cltv expiry delta // the update add htlc's cltv expiry minus cltv expiry delta for the outgoing
// for the outgoing channel, we tell them the cltv expiry and the // channel, we tell them the cltv expiry and the current channel setting for
// current channel setting for the outgoing channel. // the outgoing channel.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailIncorrectCltvExpiry struct { type FailIncorrectCltvExpiry struct {
// CltvExpiry is the wrong absolute timeout in blocks, after which outgoing // CltvExpiry is the wrong absolute timeout in blocks, after which
// HTLC expires. // outgoing HTLC expires.
CltvExpiry uint32 CltvExpiry uint32
// Update is used to update information about state of the channel which // Update is used to update information about state of the channel
// caused the failure. // which caused the failure.
Update ChannelUpdate Update ChannelUpdate
} }
// NewIncorrectCltvExpiry creates new instance of the FailIncorrectCltvExpiry. // NewIncorrectCltvExpiry creates new instance of the FailIncorrectCltvExpiry.
func NewIncorrectCltvExpiry(cltvExpiry uint32, update ChannelUpdate) *FailIncorrectCltvExpiry { func NewIncorrectCltvExpiry(cltvExpiry uint32,
update ChannelUpdate) *FailIncorrectCltvExpiry {
return &FailIncorrectCltvExpiry{ return &FailIncorrectCltvExpiry{
CltvExpiry: cltvExpiry, CltvExpiry: cltvExpiry,
Update: update, Update: update,
@ -614,8 +609,6 @@ func (f *FailIncorrectCltvExpiry) Decode(r io.Reader, pver uint32) error {
return err return err
} }
// At current moment length is not used but in future we may use it to
// differ versions of the update message.
var length uint16 var length uint16
if err := readElement(r, &length); err != nil { if err := readElement(r, &length); err != nil {
return err return err
@ -633,9 +626,6 @@ func (f *FailIncorrectCltvExpiry) Encode(w io.Writer, pver uint32) error {
return err return err
} }
// We write the length here as the size of the channel updates may differ in
// the future and at times additional information is coupled (appended to or
// prepended to the channel update itself) along with the channel update.
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver))) err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
if err != nil { if err != nil {
return err return err
@ -644,17 +634,17 @@ func (f *FailIncorrectCltvExpiry) Encode(w io.Writer, pver uint32) error {
return f.Update.Encode(w, pver) return f.Update.Encode(w, pver)
} }
// FailExpiryTooSoon is returned if the ctlv-expiry is too near, we tell // FailExpiryTooSoon is returned if the ctlv-expiry is too near, we tell them
// them the the current channel setting for the outgoing channel. // the current channel setting for the outgoing channel.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailExpiryTooSoon struct { type FailExpiryTooSoon struct {
// Update is used to update information about state of the channel which // Update is used to update information about state of the channel
// caused the failure. // which caused the failure.
Update ChannelUpdate Update ChannelUpdate
} }
// NewExpiryTooSoon creates new instance of the FailExpiryTooSoon // NewExpiryTooSoon creates new instance of the FailExpiryTooSoon.
func NewExpiryTooSoon(update ChannelUpdate) *FailExpiryTooSoon { func NewExpiryTooSoon(update ChannelUpdate) *FailExpiryTooSoon {
return &FailExpiryTooSoon{ return &FailExpiryTooSoon{
Update: update, Update: update,
@ -672,8 +662,6 @@ func (f *FailExpiryTooSoon) Code() FailCode {
// //
// NOTE: Part of the Serializable interface. // NOTE: Part of the Serializable interface.
func (f *FailExpiryTooSoon) Decode(r io.Reader, pver uint32) error { func (f *FailExpiryTooSoon) Decode(r io.Reader, pver uint32) error {
// At current moment length is not used but in future we may use it to
// differ versions of the update message.
var length uint16 var length uint16
if err := readElement(r, &length); err != nil { if err := readElement(r, &length); err != nil {
return err return err
@ -687,9 +675,6 @@ func (f *FailExpiryTooSoon) Decode(r io.Reader, pver uint32) error {
// //
// NOTE: Part of the Serializable interface. // NOTE: Part of the Serializable interface.
func (f *FailExpiryTooSoon) Encode(w io.Writer, pver uint32) error { func (f *FailExpiryTooSoon) Encode(w io.Writer, pver uint32) error {
// We write the length here as the size of the channel updates may differ in
// the future and at times additional information is coupled (appended to or
// prepended to the channel update itself) along with the channel update.
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver))) err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
if err != nil { if err != nil {
return err return err
@ -698,18 +683,18 @@ func (f *FailExpiryTooSoon) Encode(w io.Writer, pver uint32) error {
return f.Update.Encode(w, pver) return f.Update.Encode(w, pver)
} }
// FailChannelDisabled is returned if the channel is disabled, we tell // FailChannelDisabled is returned if the channel is disabled, we tell them the
// them the the current channel setting for the outgoing channel. // current channel setting for the outgoing channel.
// //
// NOTE: might be return by forwarding node only. // NOTE: May only be returned by intermediate nodes.
type FailChannelDisabled struct { type FailChannelDisabled struct {
// Flags least-significant bit must be set to 0 if the creating node // Flags least-significant bit must be set to 0 if the creating node
// corresponds to the first node in the previously sent channel // corresponds to the first node in the previously sent channel
// announcement and 1 otherwise. // announcement and 1 otherwise.
Flags uint16 Flags uint16
// Update is used to update information about state of the channel which // Update is used to update information about state of the channel
// caused the failure. // which caused the failure.
Update ChannelUpdate Update ChannelUpdate
} }
@ -736,8 +721,6 @@ func (f *FailChannelDisabled) Decode(r io.Reader, pver uint32) error {
return err return err
} }
// At current moment length is not used but in future we may use it to
// differ versions of the update message.
var length uint16 var length uint16
if err := readElement(r, &length); err != nil { if err := readElement(r, &length); err != nil {
return err return err
@ -755,9 +738,6 @@ func (f *FailChannelDisabled) Encode(w io.Writer, pver uint32) error {
return err return err
} }
// We write the length here as the size of the channel updates may differ in
// the future and at times additional information is coupled (appended to or
// prepended to the channel update itself) along with the channel update.
err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver))) err := writeElement(w, uint16(f.Update.MaxPayloadLength(pver)))
if err != nil { if err != nil {
return err return err
@ -771,8 +751,8 @@ func (f *FailChannelDisabled) Encode(w io.Writer, pver uint32) error {
// //
// NOTE: might be returned by final node only. // NOTE: might be returned by final node only.
type FailFinalIncorrectCltvExpiry struct { type FailFinalIncorrectCltvExpiry struct {
// CltvExpiry is the wrong absolute timeout in blocks, after which outgoing // CltvExpiry is the wrong absolute timeout in blocks, after which
// HTLC expires. // outgoing HTLC expires.
CltvExpiry uint32 CltvExpiry uint32
} }
@ -805,10 +785,10 @@ func (f *FailFinalIncorrectCltvExpiry) Encode(w io.Writer, pver uint32) error {
return writeElement(w, f.CltvExpiry) return writeElement(w, f.CltvExpiry)
} }
// FailFinalIncorrectHtlcAmount is returned if the amt_to_forward is // FailFinalIncorrectHtlcAmount is returned if the amt_to_forward is higher
// higher than incoming_htlc_amt of the HTLC at the final hop. // than incoming_htlc_amt of the HTLC at the final hop.
// //
// NOTE: might be returned by final node only. // NOTE: May only be returned by the final node.
type FailFinalIncorrectHtlcAmount struct { type FailFinalIncorrectHtlcAmount struct {
// IncomingHTLCAmount is the wrong forwarded htlc amount. // IncomingHTLCAmount is the wrong forwarded htlc amount.
IncomingHTLCAmount btcutil.Amount IncomingHTLCAmount btcutil.Amount
@ -843,8 +823,8 @@ func (f *FailFinalIncorrectHtlcAmount) Encode(w io.Writer, pver uint32) error {
return writeElement(w, f.IncomingHTLCAmount) return writeElement(w, f.IncomingHTLCAmount)
} }
// DecodeFailure decodes, validates, and parses the lnwire onion failure, for the // DecodeFailure decodes, validates, and parses the lnwire onion failure, for
// provided protocol version. // the provided protocol version.
func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) { func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) {
// Start processing the failure message by reading the code. // Start processing the failure message by reading the code.
var code uint16 var code uint16
@ -852,14 +832,14 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) {
return nil, err return nil, err
} }
// Create the empty failure by given code and populate the failure // Create the empty failure by given code and populate the failure with
// with additional data if needed. // additional data if needed.
failure, err := makeEmptyOnionError(FailCode(code)) failure, err := makeEmptyOnionError(FailCode(code))
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Read failure length, check its size and read the failure message // Read the failure length, check its size and read the failure message
// in order to check padding afterwards. // in order to check padding afterwards.
var failureLength uint16 var failureLength uint16
if err := readElement(r, &failureLength); err != nil { if err := readElement(r, &failureLength); err != nil {
@ -885,7 +865,8 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) {
return failure, nil return failure, nil
} }
// EncodeFailure encodes, including the necessary onion failure header information. // EncodeFailure encodes, including the necessary onion failure header
// information.
func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error { func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error {
var failureMessageBuffer bytes.Buffer var failureMessageBuffer bytes.Buffer

@ -244,16 +244,17 @@ func newServer(listenAddrs []string, chanDB *channeldb.DB, cc *chainControl,
htlcAdd *lnwire.UpdateAddHTLC, htlcAdd *lnwire.UpdateAddHTLC,
circuit *sphinx.Circuit) ([32]byte, error) { circuit *sphinx.Circuit) ([32]byte, error) {
// Initialize the data obfuscator in order to be able to decode the // Using the created circuit, initialize the error
// onion failure and wrap it so that we could process lnwire onion // decryptor so we can parse+decode any failures
// failures. // incurred by this payment within the switch.
failureDeobfuscator := &htlcswitch.FailureDeobfuscator{ errorDecryptor := &htlcswitch.FailureDeobfuscator{
OnionDeobfuscator: sphinx.NewOnionDeobfuscator(circuit), OnionDeobfuscator: sphinx.NewOnionDeobfuscator(circuit),
} }
var firstHopPub [33]byte var firstHopPub [33]byte
copy(firstHopPub[:], firstHop.SerializeCompressed()) copy(firstHopPub[:], firstHop.SerializeCompressed())
return s.htlcSwitch.SendHTLC(firstHopPub, htlcAdd, failureDeobfuscator)
return s.htlcSwitch.SendHTLC(firstHopPub, htlcAdd, errorDecryptor)
}, },
}) })
if err != nil { if err != nil {