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

     1  package htlcswitch
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/decred/dcrlnd/channeldb"
    10  	"github.com/decred/dcrlnd/htlcswitch/hop"
    11  	"github.com/decred/dcrlnd/lntypes"
    12  	"github.com/decred/dcrlnd/lnwire"
    13  	"github.com/decred/dcrlnd/subscribe"
    14  )
    15  
    16  // HtlcNotifier notifies clients of htlc forwards, failures and settles for
    17  // htlcs that the switch handles. It takes subscriptions for its events and
    18  // notifies them when htlc events occur. These are served on a best-effort
    19  // basis; events are not persisted, delivery is not guaranteed (in the event
    20  // of a crash in the switch, forward events may be lost) and some events may
    21  // be replayed upon restart. Events consumed from this package should be
    22  // de-duplicated by the htlc's unique combination of incoming+outgoing circuit
    23  // and not relied upon for critical operations.
    24  //
    25  // The htlc notifier sends the following kinds of events:
    26  // Forwarding Event:
    27  // - Represents a htlc which is forwarded onward from our node.
    28  // - Present for htlc forwards through our node and local sends.
    29  //
    30  // Link Failure Event:
    31  //   - Indicates that a htlc has failed on our incoming or outgoing link,
    32  //     with an incoming boolean which indicates where the failure occurred.
    33  //   - Incoming link failures are present for failed attempts to pay one of
    34  //     our invoices (insufficient amount or mpp timeout, for example) and for
    35  //     forwards that we cannot decode to forward onwards.
    36  //   - Outgoing link failures are present for forwards or local payments that
    37  //     do not meet our outgoing link's policy (insufficient fees, for example)
    38  //     and when we fail to forward the payment on (insufficient outgoing
    39  //     capacity, or an unknown outgoing link).
    40  //
    41  // Forwarding Failure Event:
    42  //   - Forwarding failures indicate that a htlc we forwarded has failed at
    43  //     another node down the route.
    44  //   - Present for local sends and htlc forwards which fail after they left
    45  //     our node.
    46  //
    47  // Settle event:
    48  //   - Settle events are present when a htlc which we added is settled through
    49  //     the release of a preimage.
    50  //   - Present for local receives, and successful local sends or forwards.
    51  //
    52  // Each htlc is identified by its incoming and outgoing circuit key. Htlcs,
    53  // and their subsequent settles or fails, can be identified by the combination
    54  // of incoming and outgoing circuits. Note that receives to our node will
    55  // have a zero outgoing circuit key because the htlc terminates at our
    56  // node, and sends from our node will have a zero incoming circuit key because
    57  // the send originates at our node.
    58  type HtlcNotifier struct {
    59  	started sync.Once
    60  	stopped sync.Once
    61  
    62  	// now returns the current time, it is set in the htlcnotifier to allow
    63  	// for timestamp mocking in tests.
    64  	now func() time.Time
    65  
    66  	ntfnServer *subscribe.Server
    67  }
    68  
    69  // NewHtlcNotifier creates a new HtlcNotifier which gets htlc forwarded,
    70  // failed and settled events from links our node has established with peers
    71  // and sends notifications to subscribing clients.
    72  func NewHtlcNotifier(now func() time.Time) *HtlcNotifier {
    73  	return &HtlcNotifier{
    74  		now:        now,
    75  		ntfnServer: subscribe.NewServer(),
    76  	}
    77  }
    78  
    79  // Start starts the HtlcNotifier and all goroutines it needs to consume
    80  // events and provide subscriptions to clients.
    81  func (h *HtlcNotifier) Start() error {
    82  	var err error
    83  	h.started.Do(func() {
    84  		log.Trace("HtlcNotifier starting")
    85  		err = h.ntfnServer.Start()
    86  	})
    87  	return err
    88  }
    89  
    90  // Stop signals the notifier for a graceful shutdown.
    91  func (h *HtlcNotifier) Stop() error {
    92  	var err error
    93  	h.stopped.Do(func() {
    94  		log.Info("HtlcNotifier shutting down")
    95  		if err = h.ntfnServer.Stop(); err != nil {
    96  			log.Warnf("error stopping htlc notifier: %v", err)
    97  		}
    98  	})
    99  	return err
   100  }
   101  
   102  // SubscribeHtlcEvents returns a subscribe.Client that will receive updates
   103  // any time the server is made aware of a new event.
   104  func (h *HtlcNotifier) SubscribeHtlcEvents() (*subscribe.Client, error) {
   105  	return h.ntfnServer.Subscribe()
   106  }
   107  
   108  // HtlcKey uniquely identifies the htlc.
   109  type HtlcKey struct {
   110  	// IncomingCircuit is the channel an htlc id of the incoming htlc.
   111  	IncomingCircuit channeldb.CircuitKey
   112  
   113  	// OutgoingCircuit is the channel and htlc id of the outgoing htlc.
   114  	OutgoingCircuit channeldb.CircuitKey
   115  }
   116  
   117  // String returns a string representation of a htlc key.
   118  func (k HtlcKey) String() string {
   119  	switch {
   120  	case k.IncomingCircuit.ChanID == hop.Source:
   121  		return k.OutgoingCircuit.String()
   122  
   123  	case k.OutgoingCircuit.ChanID == hop.Exit:
   124  		return k.IncomingCircuit.String()
   125  
   126  	default:
   127  		return fmt.Sprintf("%v -> %v", k.IncomingCircuit,
   128  			k.OutgoingCircuit)
   129  	}
   130  }
   131  
   132  // HtlcInfo provides the details of a htlc that our node has processed. For
   133  // forwards, incoming and outgoing values are set, whereas sends and receives
   134  // will only have outgoing or incoming details set.
   135  type HtlcInfo struct {
   136  	// IncomingTimelock is the time lock of the htlc on our incoming
   137  	// channel.
   138  	IncomingTimeLock uint32
   139  
   140  	// OutgoingTimelock is the time lock the htlc on our outgoing channel.
   141  	OutgoingTimeLock uint32
   142  
   143  	// IncomingAmt is the amount of the htlc on our incoming channel.
   144  	IncomingAmt lnwire.MilliAtom
   145  
   146  	// OutgoingAmt is the amount of the htlc on our outgoing channel.
   147  	OutgoingAmt lnwire.MilliAtom
   148  }
   149  
   150  // String returns a string representation of a htlc.
   151  func (h HtlcInfo) String() string {
   152  	var details []string
   153  
   154  	// If the incoming information is not zero, as is the case for a send,
   155  	// we include the incoming amount and timelock.
   156  	if h.IncomingAmt != 0 || h.IncomingTimeLock != 0 {
   157  		str := fmt.Sprintf("incoming amount: %v, "+
   158  			"incoming timelock: %v", h.IncomingAmt,
   159  			h.IncomingTimeLock)
   160  
   161  		details = append(details, str)
   162  	}
   163  
   164  	// If the outgoing information is not zero, as is the case for a
   165  	// receive, we include the outgoing amount and timelock.
   166  	if h.OutgoingAmt != 0 || h.OutgoingTimeLock != 0 {
   167  		str := fmt.Sprintf("outgoing amount: %v, "+
   168  			"outgoing timelock: %v", h.OutgoingAmt,
   169  			h.OutgoingTimeLock)
   170  
   171  		details = append(details, str)
   172  	}
   173  
   174  	return strings.Join(details, ", ")
   175  }
   176  
   177  // HtlcEventType represents the type of event that a htlc was part of.
   178  type HtlcEventType int
   179  
   180  const (
   181  	// HtlcEventTypeSend represents a htlc that was part of a send from
   182  	// our node.
   183  	HtlcEventTypeSend HtlcEventType = iota
   184  
   185  	// HtlcEventTypeReceive represents a htlc that was part of a receive
   186  	// to our node.
   187  	HtlcEventTypeReceive
   188  
   189  	// HtlcEventTypeForward represents a htlc that was forwarded through
   190  	// our node.
   191  	HtlcEventTypeForward
   192  )
   193  
   194  // String returns a string representation of a htlc event type.
   195  func (h HtlcEventType) String() string {
   196  	switch h {
   197  	case HtlcEventTypeSend:
   198  		return "send"
   199  
   200  	case HtlcEventTypeReceive:
   201  		return "receive"
   202  
   203  	case HtlcEventTypeForward:
   204  		return "forward"
   205  
   206  	default:
   207  		return "unknown"
   208  	}
   209  }
   210  
   211  // ForwardingEvent represents a htlc that was forwarded onwards from our node.
   212  // Sends which originate from our node will report forward events with zero
   213  // incoming circuits in their htlc key.
   214  type ForwardingEvent struct {
   215  	// HtlcKey uniquely identifies the htlc, and can be used to match the
   216  	// forwarding event with subsequent settle/fail events.
   217  	HtlcKey
   218  
   219  	// HtlcInfo contains details about the htlc.
   220  	HtlcInfo
   221  
   222  	// HtlcEventType classifies the event as part of a local send or
   223  	// receive, or as part of a forward.
   224  	HtlcEventType
   225  
   226  	// Timestamp is the time when this htlc was forwarded.
   227  	Timestamp time.Time
   228  }
   229  
   230  // LinkFailEvent describes a htlc that failed on our incoming or outgoing
   231  // link. The incoming bool is true for failures on incoming links, and false
   232  // for failures on outgoing links. The failure reason is provided by a lnwire
   233  // failure message which is enriched with a failure detail in the cases where
   234  // the wire failure message does not contain full information about the
   235  // failure.
   236  type LinkFailEvent struct {
   237  	// HtlcKey uniquely identifies the htlc.
   238  	HtlcKey
   239  
   240  	// HtlcInfo contains details about the htlc.
   241  	HtlcInfo
   242  
   243  	// HtlcEventType classifies the event as part of a local send or
   244  	// receive, or as part of a forward.
   245  	HtlcEventType
   246  
   247  	// LinkError is the reason that we failed the htlc.
   248  	LinkError *LinkError
   249  
   250  	// Incoming is true if the htlc was failed on an incoming link.
   251  	// If it failed on the outgoing link, it is false.
   252  	Incoming bool
   253  
   254  	// Timestamp is the time when the link failure occurred.
   255  	Timestamp time.Time
   256  }
   257  
   258  // ForwardingFailEvent represents a htlc failure which occurred down the line
   259  // after we forwarded a htlc onwards. An error is not included in this event
   260  // because errors returned down the route are encrypted. HtlcInfo is not
   261  // reliably available for forwarding failures, so it is omitted. These events
   262  // should be matched with their corresponding forward event to obtain this
   263  // information.
   264  type ForwardingFailEvent struct {
   265  	// HtlcKey uniquely identifies the htlc, and can be used to match the
   266  	// htlc with its corresponding forwarding event.
   267  	HtlcKey
   268  
   269  	// HtlcEventType classifies the event as part of a local send or
   270  	// receive, or as part of a forward.
   271  	HtlcEventType
   272  
   273  	// Timestamp is the time when the forwarding failure was received.
   274  	Timestamp time.Time
   275  }
   276  
   277  // SettleEvent represents a htlc that was settled. HtlcInfo is not reliably
   278  // available for forwarding failures, so it is omitted. These events should
   279  // be matched with corresponding forward events or invoices (for receives)
   280  // to obtain additional information about the htlc.
   281  type SettleEvent struct {
   282  	// HtlcKey uniquely identifies the htlc, and can be used to match
   283  	// forwards with their corresponding forwarding event.
   284  	HtlcKey
   285  
   286  	// Preimage that was released for settling the htlc.
   287  	Preimage lntypes.Preimage
   288  
   289  	// HtlcEventType classifies the event as part of a local send or
   290  	// receive, or as part of a forward.
   291  	HtlcEventType
   292  
   293  	// Timestamp is the time when this htlc was settled.
   294  	Timestamp time.Time
   295  }
   296  
   297  // NotifyForwardingEvent notifies the HtlcNotifier than a htlc has been
   298  // forwarded.
   299  //
   300  // Note this is part of the htlcNotifier interface.
   301  func (h *HtlcNotifier) NotifyForwardingEvent(key HtlcKey, info HtlcInfo,
   302  	eventType HtlcEventType) {
   303  
   304  	event := &ForwardingEvent{
   305  		HtlcKey:       key,
   306  		HtlcInfo:      info,
   307  		HtlcEventType: eventType,
   308  		Timestamp:     h.now(),
   309  	}
   310  
   311  	log.Tracef("Notifying forward event: %v over %v, %v", eventType, key,
   312  		info)
   313  
   314  	if err := h.ntfnServer.SendUpdate(event); err != nil {
   315  		log.Warnf("Unable to send forwarding event: %v", err)
   316  	}
   317  }
   318  
   319  // NotifyLinkFailEvent notifies that a htlc has failed on our incoming
   320  // or outgoing link.
   321  //
   322  // Note this is part of the htlcNotifier interface.
   323  func (h *HtlcNotifier) NotifyLinkFailEvent(key HtlcKey, info HtlcInfo,
   324  	eventType HtlcEventType, linkErr *LinkError, incoming bool) {
   325  
   326  	event := &LinkFailEvent{
   327  		HtlcKey:       key,
   328  		HtlcInfo:      info,
   329  		HtlcEventType: eventType,
   330  		LinkError:     linkErr,
   331  		Incoming:      incoming,
   332  		Timestamp:     h.now(),
   333  	}
   334  
   335  	log.Tracef("Notifying link failure event: %v over %v, %v", eventType,
   336  		key, info)
   337  
   338  	if err := h.ntfnServer.SendUpdate(event); err != nil {
   339  		log.Warnf("Unable to send link fail event: %v", err)
   340  	}
   341  }
   342  
   343  // NotifyForwardingFailEvent notifies the HtlcNotifier that a htlc we
   344  // forwarded has failed down the line.
   345  //
   346  // Note this is part of the htlcNotifier interface.
   347  func (h *HtlcNotifier) NotifyForwardingFailEvent(key HtlcKey,
   348  	eventType HtlcEventType) {
   349  
   350  	event := &ForwardingFailEvent{
   351  		HtlcKey:       key,
   352  		HtlcEventType: eventType,
   353  		Timestamp:     h.now(),
   354  	}
   355  
   356  	log.Tracef("Notifying forwarding failure event: %v over %v", eventType,
   357  		key)
   358  
   359  	if err := h.ntfnServer.SendUpdate(event); err != nil {
   360  		log.Warnf("Unable to send forwarding fail event: %v", err)
   361  	}
   362  }
   363  
   364  // NotifySettleEvent notifies the HtlcNotifier that a htlc that we committed
   365  // to as part of a forward or a receive to our node has been settled.
   366  //
   367  // Note this is part of the htlcNotifier interface.
   368  func (h *HtlcNotifier) NotifySettleEvent(key HtlcKey,
   369  	preimage lntypes.Preimage, eventType HtlcEventType) {
   370  
   371  	event := &SettleEvent{
   372  		HtlcKey:       key,
   373  		Preimage:      preimage,
   374  		HtlcEventType: eventType,
   375  		Timestamp:     h.now(),
   376  	}
   377  
   378  	log.Tracef("Notifying settle event: %v over %v", eventType, key)
   379  
   380  	if err := h.ntfnServer.SendUpdate(event); err != nil {
   381  		log.Warnf("Unable to send settle event: %v", err)
   382  	}
   383  }
   384  
   385  // newHtlc key returns a htlc key for the packet provided. If the packet
   386  // has a zero incoming channel ID, the packet is for one of our own sends,
   387  // which has the payment id stashed in the incoming htlc id. If this is the
   388  // case, we replace the incoming htlc id with zero so that the notifier
   389  // consistently reports zero circuit keys for events that terminate or
   390  // originate at our node.
   391  func newHtlcKey(pkt *htlcPacket) HtlcKey {
   392  	htlcKey := HtlcKey{
   393  		IncomingCircuit: channeldb.CircuitKey{
   394  			ChanID: pkt.incomingChanID,
   395  			HtlcID: pkt.incomingHTLCID,
   396  		},
   397  		OutgoingCircuit: CircuitKey{
   398  			ChanID: pkt.outgoingChanID,
   399  			HtlcID: pkt.outgoingHTLCID,
   400  		},
   401  	}
   402  
   403  	// If the packet has a zero incoming channel ID, it is a send that was
   404  	// initiated at our node. If this is the case, our internal pid is in
   405  	// the incoming htlc ID, so we overwrite it with 0 for notification
   406  	// purposes.
   407  	if pkt.incomingChanID == hop.Source {
   408  		htlcKey.IncomingCircuit.HtlcID = 0
   409  	}
   410  
   411  	return htlcKey
   412  }
   413  
   414  // newHtlcInfo returns HtlcInfo for the packet provided.
   415  func newHtlcInfo(pkt *htlcPacket) HtlcInfo {
   416  	return HtlcInfo{
   417  		IncomingTimeLock: pkt.incomingTimeout,
   418  		OutgoingTimeLock: pkt.outgoingTimeout,
   419  		IncomingAmt:      pkt.incomingAmount,
   420  		OutgoingAmt:      pkt.amount,
   421  	}
   422  }
   423  
   424  // getEventType returns the htlc type based on the fields set in the htlc
   425  // packet. Sends that originate at our node have the source (zero) incoming
   426  // channel ID. Receives to our node have the exit (zero) outgoing channel ID
   427  // and forwards have both fields set.
   428  func getEventType(pkt *htlcPacket) HtlcEventType {
   429  	switch {
   430  	case pkt.incomingChanID == hop.Source:
   431  		return HtlcEventTypeSend
   432  
   433  	case pkt.outgoingChanID == hop.Exit:
   434  		return HtlcEventTypeReceive
   435  
   436  	default:
   437  		return HtlcEventTypeForward
   438  	}
   439  }