github.com/decred/dcrlnd@v0.7.6/htlcswitch/failure.go (about)

     1  package htlcswitch
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/decred/dcrlnd/htlcswitch/hop"
     8  	"github.com/decred/dcrlnd/lnwire"
     9  	sphinx "github.com/decred/lightning-onion/v4"
    10  )
    11  
    12  // ClearTextError is an interface which is implemented by errors that occur
    13  // when we know the underlying wire failure message. These errors are the
    14  // opposite to opaque errors which are onion-encrypted blobs only understandable
    15  // to the initiating node. ClearTextErrors are used when we fail a htlc at our
    16  // node, or one of our initiated payments failed and we can decrypt the onion
    17  // encrypted error fully.
    18  type ClearTextError interface {
    19  	error
    20  
    21  	// WireMessage extracts a valid wire failure message from an internal
    22  	// error which may contain additional metadata (which should not be
    23  	// exposed to the network). This value may be nil in the case where
    24  	// an unknown wire error is returned by one of our peers.
    25  	WireMessage() lnwire.FailureMessage
    26  }
    27  
    28  // LinkError is an implementation of the ClearTextError interface which
    29  // represents failures that occur on our incoming or outgoing link.
    30  type LinkError struct {
    31  	// msg returns the wire failure associated with the error.
    32  	// This value should *not* be nil, because we should always
    33  	// know the failure type for failures which occur at our own
    34  	// node.
    35  	msg lnwire.FailureMessage
    36  
    37  	// FailureDetail enriches the wire error with additional information.
    38  	FailureDetail
    39  }
    40  
    41  // NewLinkError returns a LinkError with the failure message provided.
    42  // The failure message provided should *not* be nil, because we should
    43  // always know the failure type for failures which occur at our own node.
    44  func NewLinkError(msg lnwire.FailureMessage) *LinkError {
    45  	return &LinkError{msg: msg}
    46  }
    47  
    48  // NewDetailedLinkError returns a link error that enriches a wire message with
    49  // a failure detail.
    50  func NewDetailedLinkError(msg lnwire.FailureMessage,
    51  	detail FailureDetail) *LinkError {
    52  
    53  	return &LinkError{
    54  		msg:           msg,
    55  		FailureDetail: detail,
    56  	}
    57  }
    58  
    59  // WireMessage extracts a valid wire failure message from an internal
    60  // error which may contain additional metadata (which should not be
    61  // exposed to the network). This value should never be nil for LinkErrors,
    62  // because we are the ones failing the htlc.
    63  //
    64  // Note this is part of the ClearTextError interface.
    65  func (l *LinkError) WireMessage() lnwire.FailureMessage {
    66  	return l.msg
    67  }
    68  
    69  // Error returns the string representation of a link error.
    70  //
    71  // Note this is part of the ClearTextError interface.
    72  func (l *LinkError) Error() string {
    73  	// If the link error has no failure detail, return the wire message's
    74  	// error.
    75  	if l.FailureDetail == nil {
    76  		return l.msg.Error()
    77  	}
    78  
    79  	return l.FailureDetail.FailureString()
    80  }
    81  
    82  // ForwardingError wraps an lnwire.FailureMessage in a struct that also
    83  // includes the source of the error.
    84  type ForwardingError struct {
    85  	// FailureSourceIdx is the index of the node that sent the failure.
    86  	// With this information, the dispatcher of a payment can modify their
    87  	// set of candidate routes in response to the type of failure
    88  	// extracted. Index zero is the self node.
    89  	FailureSourceIdx int
    90  
    91  	// msg is the wire message associated with the error. This value may
    92  	// be nil in the case where we fail to decode failure message sent by
    93  	// a peer.
    94  	msg lnwire.FailureMessage
    95  }
    96  
    97  // WireMessage extracts a valid wire failure message from an internal
    98  // error which may contain additional metadata (which should not be
    99  // exposed to the network). This value may be nil in the case where
   100  // an unknown wire error is returned by one of our peers.
   101  //
   102  // Note this is part of the ClearTextError interface.
   103  func (f *ForwardingError) WireMessage() lnwire.FailureMessage {
   104  	return f.msg
   105  }
   106  
   107  // Error implements the built-in error interface. We use this method to allow
   108  // the switch or any callers to insert additional context to the error message
   109  // returned.
   110  func (f *ForwardingError) Error() string {
   111  	return fmt.Sprintf(
   112  		"%v@%v", f.msg, f.FailureSourceIdx,
   113  	)
   114  }
   115  
   116  // NewForwardingError creates a new payment error which wraps a wire error
   117  // with additional metadata.
   118  func NewForwardingError(failure lnwire.FailureMessage,
   119  	index int) *ForwardingError {
   120  
   121  	return &ForwardingError{
   122  		FailureSourceIdx: index,
   123  		msg:              failure,
   124  	}
   125  }
   126  
   127  // NewUnknownForwardingError returns a forwarding error which has a nil failure
   128  // message. This constructor should only be used in the case where we cannot
   129  // decode the failure we have received from a peer.
   130  func NewUnknownForwardingError(index int) *ForwardingError {
   131  	return &ForwardingError{
   132  		FailureSourceIdx: index,
   133  	}
   134  }
   135  
   136  // ErrorDecrypter is an interface that is used to decrypt the onion encrypted
   137  // failure reason an extra out a well formed error.
   138  type ErrorDecrypter interface {
   139  	// DecryptError peels off each layer of onion encryption from the first
   140  	// hop, to the source of the error. A fully populated
   141  	// lnwire.FailureMessage is returned along with the source of the
   142  	// error.
   143  	DecryptError(lnwire.OpaqueReason) (*ForwardingError, error)
   144  }
   145  
   146  // UnknownEncrypterType is an error message used to signal that an unexpected
   147  // EncrypterType was encountered during decoding.
   148  type UnknownEncrypterType hop.EncrypterType
   149  
   150  // Error returns a formatted error indicating the invalid EncrypterType.
   151  func (e UnknownEncrypterType) Error() string {
   152  	return fmt.Sprintf("unknown error encrypter type: %d", e)
   153  }
   154  
   155  // OnionErrorDecrypter is the interface that provides onion level error
   156  // decryption.
   157  type OnionErrorDecrypter interface {
   158  	// DecryptError attempts to decrypt the passed encrypted error response.
   159  	// The onion failure is encrypted in backward manner, starting from the
   160  	// node where error have occurred. As a result, in order to decrypt the
   161  	// error we need get all shared secret and apply decryption in the
   162  	// reverse order.
   163  	DecryptError(encryptedData []byte) (*sphinx.DecryptedError, error)
   164  }
   165  
   166  // SphinxErrorDecrypter wraps the sphinx data SphinxErrorDecrypter and maps the
   167  // returned errors to concrete lnwire.FailureMessage instances.
   168  type SphinxErrorDecrypter struct {
   169  	OnionErrorDecrypter
   170  }
   171  
   172  // DecryptError peels off each layer of onion encryption from the first hop, to
   173  // the source of the error. A fully populated lnwire.FailureMessage is returned
   174  // along with the source of the error.
   175  //
   176  // NOTE: Part of the ErrorDecrypter interface.
   177  func (s *SphinxErrorDecrypter) DecryptError(reason lnwire.OpaqueReason) (
   178  	*ForwardingError, error) {
   179  
   180  	failure, err := s.OnionErrorDecrypter.DecryptError(reason)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	// Decode the failure. If an error occurs, we leave the failure message
   186  	// field nil.
   187  	r := bytes.NewReader(failure.Message)
   188  	failureMsg, err := lnwire.DecodeFailure(r, 0)
   189  	if err != nil {
   190  		return NewUnknownForwardingError(failure.SenderIdx), nil
   191  	}
   192  
   193  	return NewForwardingError(failureMsg, failure.SenderIdx), nil
   194  }
   195  
   196  // A compile time check to ensure ErrorDecrypter implements the Deobfuscator
   197  // interface.
   198  var _ ErrorDecrypter = (*SphinxErrorDecrypter)(nil)