/ htlcswitch / interfaces.go
interfaces.go
  1  package htlcswitch
  2  
  3  import (
  4  	"context"
  5  
  6  	"github.com/btcsuite/btcd/btcutil"
  7  	"github.com/btcsuite/btcd/wire"
  8  	"github.com/lightningnetwork/lnd/channeldb"
  9  	"github.com/lightningnetwork/lnd/fn/v2"
 10  	"github.com/lightningnetwork/lnd/graph/db/models"
 11  	"github.com/lightningnetwork/lnd/invoices"
 12  	"github.com/lightningnetwork/lnd/lntypes"
 13  	"github.com/lightningnetwork/lnd/lnwallet"
 14  	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 15  	"github.com/lightningnetwork/lnd/lnwire"
 16  	"github.com/lightningnetwork/lnd/record"
 17  	"github.com/lightningnetwork/lnd/routing/route"
 18  	"github.com/lightningnetwork/lnd/tlv"
 19  )
 20  
 21  // InvoiceDatabase is an interface which represents the persistent subsystem
 22  // which may search, lookup and settle invoices.
 23  type InvoiceDatabase interface {
 24  	// LookupInvoice attempts to look up an invoice according to its 32
 25  	// byte payment hash.
 26  	LookupInvoice(context.Context, lntypes.Hash) (invoices.Invoice, error)
 27  
 28  	// NotifyExitHopHtlc attempts to mark an invoice as settled. If the
 29  	// invoice is a debug invoice, then this method is a noop as debug
 30  	// invoices are never fully settled. The return value describes how the
 31  	// htlc should be resolved. If the htlc cannot be resolved immediately,
 32  	// the resolution is sent on the passed in hodlChan later. The eob
 33  	// field passes the entire onion hop payload into the invoice registry
 34  	// for decoding purposes.
 35  	NotifyExitHopHtlc(payHash lntypes.Hash, paidAmount lnwire.MilliSatoshi,
 36  		expiry uint32, currentHeight int32,
 37  		circuitKey models.CircuitKey, hodlChan chan<- interface{},
 38  		wireCustomRecords lnwire.CustomRecords,
 39  		payload invoices.Payload) (invoices.HtlcResolution, error)
 40  
 41  	// CancelInvoice attempts to cancel the invoice corresponding to the
 42  	// passed payment hash.
 43  	CancelInvoice(ctx context.Context, payHash lntypes.Hash) error
 44  
 45  	// SettleHodlInvoice settles a hold invoice.
 46  	SettleHodlInvoice(ctx context.Context, preimage lntypes.Preimage) error
 47  
 48  	// HodlUnsubscribeAll unsubscribes from all htlc resolutions.
 49  	HodlUnsubscribeAll(subscriber chan<- interface{})
 50  }
 51  
 52  // packetHandler is an interface used exclusively by the Switch to handle
 53  // htlcPacket and pass them to the link implementation.
 54  type packetHandler interface {
 55  	// handleSwitchPacket handles the switch packets. These packets might
 56  	// be forwarded to us from another channel link in case the htlc
 57  	// update came from another peer or if the update was created by user
 58  	// initially.
 59  	//
 60  	// NOTE: This function should block as little as possible.
 61  	handleSwitchPacket(*htlcPacket) error
 62  }
 63  
 64  // dustHandler is an interface used exclusively by the Switch to evaluate
 65  // whether a link has too much dust exposure.
 66  type dustHandler interface {
 67  	// getDustSum returns the dust sum on either the local or remote
 68  	// commitment. An optional fee parameter can be passed in which is used
 69  	// to calculate the dust sum.
 70  	getDustSum(whoseCommit lntypes.ChannelParty,
 71  		fee fn.Option[chainfee.SatPerKWeight]) lnwire.MilliSatoshi
 72  
 73  	// getFeeRate returns the current channel feerate.
 74  	getFeeRate() chainfee.SatPerKWeight
 75  
 76  	// getDustClosure returns a closure that can evaluate whether a passed
 77  	// HTLC is dust.
 78  	getDustClosure() dustClosure
 79  
 80  	// getCommitFee returns the commitment fee in satoshis from either the
 81  	// local or remote commitment. This does not include dust.
 82  	getCommitFee(remote bool) btcutil.Amount
 83  }
 84  
 85  // scidAliasHandler is an interface that the ChannelLink implements so it can
 86  // properly handle option_scid_alias channels.
 87  type scidAliasHandler interface {
 88  	// attachFailAliasUpdate allows the link to properly fail incoming
 89  	// HTLCs on option_scid_alias channels.
 90  	attachFailAliasUpdate(failClosure func(
 91  		sid lnwire.ShortChannelID,
 92  		incoming bool) *lnwire.ChannelUpdate1)
 93  
 94  	// getAliases fetches the link's underlying aliases. This is used by
 95  	// the Switch to determine whether to forward an HTLC and where to
 96  	// forward an HTLC.
 97  	getAliases() []lnwire.ShortChannelID
 98  
 99  	// isZeroConf returns whether or not the underlying channel is a
100  	// zero-conf channel.
101  	isZeroConf() bool
102  
103  	// negotiatedAliasFeature returns whether the option-scid-alias feature
104  	// bit was negotiated.
105  	negotiatedAliasFeature() bool
106  
107  	// confirmedScid returns the confirmed SCID for a zero-conf channel.
108  	confirmedScid() lnwire.ShortChannelID
109  
110  	// zeroConfConfirmed returns whether or not the zero-conf channel has
111  	// confirmed.
112  	zeroConfConfirmed() bool
113  }
114  
115  // ChannelUpdateHandler is an interface that provides methods that allow
116  // sending lnwire.Message to the underlying link as well as querying state.
117  type ChannelUpdateHandler interface {
118  	// HandleChannelUpdate handles the htlc requests as settle/add/fail
119  	// which sent to us from remote peer we have a channel with.
120  	//
121  	// NOTE: This function MUST be non-blocking (or block as little as
122  	// possible).
123  	HandleChannelUpdate(lnwire.Message)
124  
125  	// ChanID returns the channel ID for the channel link. The channel ID
126  	// is a more compact representation of a channel's full outpoint.
127  	ChanID() lnwire.ChannelID
128  
129  	// Bandwidth returns the amount of milli-satoshis which current link
130  	// might pass through channel link. The value returned from this method
131  	// represents the up to date available flow through the channel. This
132  	// takes into account any forwarded but un-cleared HTLC's, and any
133  	// HTLC's which have been set to the over flow queue.
134  	Bandwidth() lnwire.MilliSatoshi
135  
136  	// EligibleToForward returns a bool indicating if the channel is able
137  	// to actively accept requests to forward HTLC's. A channel may be
138  	// active, but not able to forward HTLC's if it hasn't yet finalized
139  	// the pre-channel operation protocol with the remote peer. The switch
140  	// will use this function in forwarding decisions accordingly.
141  	EligibleToForward() bool
142  
143  	// MayAddOutgoingHtlc returns an error if we may not add an outgoing
144  	// htlc to the channel, taking the amount of the htlc to add as a
145  	// parameter.
146  	MayAddOutgoingHtlc(lnwire.MilliSatoshi) error
147  
148  	// EnableAdds sets the ChannelUpdateHandler state to allow
149  	// UpdateAddHtlc's in the specified direction. It returns true if the
150  	// state was changed and false if the desired state was already set
151  	// before the method was called.
152  	EnableAdds(direction LinkDirection) bool
153  
154  	// DisableAdds sets the ChannelUpdateHandler state to allow
155  	// UpdateAddHtlc's in the specified direction. It returns true if the
156  	// state was changed and false if the desired state was already set
157  	// before the method was called.
158  	DisableAdds(direction LinkDirection) bool
159  
160  	// IsFlushing returns true when UpdateAddHtlc's are disabled in the
161  	// direction of the argument.
162  	IsFlushing(direction LinkDirection) bool
163  
164  	// OnFlushedOnce adds a hook that will be called the next time the
165  	// channel state reaches zero htlcs. This hook will only ever be called
166  	// once. If the channel state already has zero htlcs, then this will be
167  	// called immediately.
168  	OnFlushedOnce(func())
169  
170  	// OnCommitOnce adds a hook that will be called the next time a
171  	// CommitSig message is sent in the argument's LinkDirection. This hook
172  	// will only ever be called once. If no CommitSig is owed in the
173  	// argument's LinkDirection, then we will call this hook immediately.
174  	OnCommitOnce(LinkDirection, func())
175  
176  	// InitStfu allows us to initiate quiescence on this link. It returns
177  	// a receive only channel that will block until quiescence has been
178  	// achieved, or definitively fails. The return value is the
179  	// ChannelParty who holds the role of initiator or Err if the operation
180  	// fails.
181  	//
182  	// This operation has been added to allow channels to be quiesced via
183  	// RPC. It may be removed or reworked in the future as RPC initiated
184  	// quiescence is a holdover until we have downstream protocols that use
185  	// it.
186  	InitStfu() <-chan fn.Result[lntypes.ChannelParty]
187  }
188  
189  // CommitHookID is a value that is used to uniquely identify hooks in the
190  // ChannelUpdateHandler's commitment update lifecycle. You should never need to
191  // construct one of these by hand, nor should you try.
192  type CommitHookID uint64
193  
194  // FlushHookID is a value that is used to uniquely identify hooks in the
195  // ChannelUpdateHandler's flush lifecycle. You should never need to construct
196  // one of these by hand, nor should you try.
197  type FlushHookID uint64
198  
199  // LinkDirection is used to query and change any link state on a per-direction
200  // basis.
201  type LinkDirection = bool
202  
203  const (
204  	// Incoming is the direction from the remote peer to our node.
205  	Incoming LinkDirection = false
206  
207  	// Outgoing is the direction from our node to the remote peer.
208  	Outgoing LinkDirection = true
209  )
210  
211  // OptionalBandwidth is a type alias for the result of a bandwidth query that
212  // may return a bandwidth value or fn.None if the bandwidth is not available or
213  // not applicable. IsHandled is set to false if the external traffic shaper does
214  // not handle the channel in question.
215  type OptionalBandwidth struct {
216  	// IsHandled is true if the external traffic shaper handles the channel.
217  	// If this is false, then the bandwidth value is not applicable.
218  	IsHandled bool
219  
220  	// Bandwidth is the available bandwidth for the channel, as determined
221  	// by the external traffic shaper. If the external traffic shaper is not
222  	// handling the channel, this value will be fn.None.
223  	Bandwidth fn.Option[lnwire.MilliSatoshi]
224  }
225  
226  // ChannelLink is an interface which represents the subsystem for managing the
227  // incoming htlc requests, applying the changes to the channel, and also
228  // propagating/forwarding it to htlc switch.
229  //
230  //	abstraction level
231  //	     ^
232  //	     |
233  //	     | - - - - - - - - - - - - Lightning - - - - - - - - - - - - -
234  //	     |
235  //	     | (Switch)		     (Switch)		       (Switch)
236  //	     |  Alice <-- channel link --> Bob <-- channel link --> Carol
237  //	     |
238  //	     | - - - - - - - - - - - - - TCP - - - - - - - - - - - - - - -
239  //	     |
240  //	     |  (Peer) 		     (Peer)	                (Peer)
241  //	     |  Alice <----- tcp conn --> Bob <---- tcp conn -----> Carol
242  //	     |
243  type ChannelLink interface {
244  	// TODO(roasbeef): modify interface to embed mail boxes?
245  
246  	// Embed the packetHandler interface.
247  	packetHandler
248  
249  	// Embed the ChannelUpdateHandler interface.
250  	ChannelUpdateHandler
251  
252  	// Embed the dustHandler interface.
253  	dustHandler
254  
255  	// Embed the scidAliasHandler interface.
256  	scidAliasHandler
257  
258  	// IsUnadvertised returns true if the underlying channel is
259  	// unadvertised.
260  	IsUnadvertised() bool
261  
262  	// ChannelPoint returns the channel outpoint for the channel link.
263  	ChannelPoint() wire.OutPoint
264  
265  	// ShortChanID returns the short channel ID for the channel link. The
266  	// short channel ID encodes the exact location in the main chain that
267  	// the original funding output can be found.
268  	ShortChanID() lnwire.ShortChannelID
269  
270  	// UpdateShortChanID updates the short channel ID for a link. This may
271  	// be required in the event that a link is created before the short
272  	// chan ID for it is known, or a re-org occurs, and the funding
273  	// transaction changes location within the chain.
274  	UpdateShortChanID() (lnwire.ShortChannelID, error)
275  
276  	// UpdateForwardingPolicy updates the forwarding policy for the target
277  	// ChannelLink. Once updated, the link will use the new forwarding
278  	// policy to govern if it an incoming HTLC should be forwarded or not.
279  	UpdateForwardingPolicy(models.ForwardingPolicy)
280  
281  	// CheckHtlcForward should return a nil error if the passed HTLC details
282  	// satisfy the current forwarding policy fo the target link. Otherwise,
283  	// a LinkError with a valid protocol failure message should be returned
284  	// in order to signal to the source of the HTLC, the policy consistency
285  	// issue.
286  	CheckHtlcForward(payHash [32]byte, incomingAmt lnwire.MilliSatoshi,
287  		amtToForward lnwire.MilliSatoshi, incomingTimeout,
288  		outgoingTimeout uint32, inboundFee models.InboundFee,
289  		heightNow uint32, scid lnwire.ShortChannelID,
290  		customRecords lnwire.CustomRecords) *LinkError
291  
292  	// CheckHtlcTransit should return a nil error if the passed HTLC details
293  	// satisfy the current channel policy.  Otherwise, a LinkError with a
294  	// valid protocol failure message should be returned in order to signal
295  	// the violation. This call is intended to be used for locally initiated
296  	// payments for which there is no corresponding incoming htlc.
297  	CheckHtlcTransit(payHash [32]byte, amt lnwire.MilliSatoshi,
298  		timeout uint32, heightNow uint32,
299  		customRecords lnwire.CustomRecords) *LinkError
300  
301  	// Stats return the statistics of channel link. Number of updates,
302  	// total sent/received milli-satoshis.
303  	Stats() (uint64, lnwire.MilliSatoshi, lnwire.MilliSatoshi)
304  
305  	// PeerPubKey returns the serialized public key of remote peer with
306  	// which we have the channel link opened.
307  	PeerPubKey() [33]byte
308  
309  	// AttachMailBox delivers an active MailBox to the link. The MailBox may
310  	// have buffered messages.
311  	AttachMailBox(MailBox)
312  
313  	// FundingCustomBlob returns the custom funding blob of the channel that
314  	// this link is associated with. The funding blob represents static
315  	// information about the channel that was created at channel funding
316  	// time.
317  	FundingCustomBlob() fn.Option[tlv.Blob]
318  
319  	// CommitmentCustomBlob returns the custom blob of the current local
320  	// commitment of the channel that this link is associated with.
321  	CommitmentCustomBlob() fn.Option[tlv.Blob]
322  
323  	// AuxBandwidth returns the bandwidth that can be used for a channel,
324  	// expressed in milli-satoshi. This might be different from the regular
325  	// BTC bandwidth for custom channels. This will always return fn.None()
326  	// for a regular (non-custom) channel.
327  	AuxBandwidth(amount lnwire.MilliSatoshi, cid lnwire.ShortChannelID,
328  		htlcBlob fn.Option[tlv.Blob],
329  		ts AuxTrafficShaper) fn.Result[OptionalBandwidth]
330  
331  	// Start starts the channel link.
332  	Start() error
333  
334  	// Stop requests the channel link to be shut down.
335  	Stop()
336  }
337  
338  // ForwardingLog is an interface that represents a time series database which
339  // keep track of all successfully completed payment circuits. Every few
340  // seconds, the switch will collate and flush out all the successful payment
341  // circuits during the last interval.
342  type ForwardingLog interface {
343  	// AddForwardingEvents is a method that should write out the set of
344  	// forwarding events in a batch to persistent storage. Outside
345  	// sub-systems can then query the contents of the log for analysis,
346  	// visualizations, etc.
347  	AddForwardingEvents([]channeldb.ForwardingEvent) error
348  }
349  
350  // TowerClient is the primary interface used by the daemon to backup pre-signed
351  // justice transactions to watchtowers.
352  type TowerClient interface {
353  	// RegisterChannel persistently initializes any channel-dependent
354  	// parameters within the client. This should be called during link
355  	// startup to ensure that the client is able to support the link during
356  	// operation.
357  	RegisterChannel(lnwire.ChannelID, channeldb.ChannelType) error
358  
359  	// BackupState initiates a request to back up a particular revoked
360  	// state. If the method returns nil, the backup is guaranteed to be
361  	// successful unless the justice transaction would create dust outputs
362  	// when trying to abide by the negotiated policy.
363  	BackupState(chanID *lnwire.ChannelID, stateNum uint64) error
364  }
365  
366  // InterceptableHtlcForwarder is the interface to set the interceptor
367  // implementation that intercepts htlc forwards.
368  type InterceptableHtlcForwarder interface {
369  	// SetInterceptor sets a ForwardInterceptor.
370  	SetInterceptor(interceptor ForwardInterceptor)
371  
372  	// Resolve resolves an intercepted packet.
373  	Resolve(res *FwdResolution) error
374  }
375  
376  // ForwardInterceptor is a function that is invoked from the switch for every
377  // incoming htlc that is intended to be forwarded. It is passed with the
378  // InterceptedForward that contains the information about the packet and a way
379  // to resolve it manually later in case it is held.
380  // The return value indicates if this handler will take control of this forward
381  // and resolve it later or let the switch execute its default behavior.
382  type ForwardInterceptor func(InterceptedPacket) error
383  
384  // InterceptedPacket contains the relevant information for the interceptor about
385  // an HTLC.
386  type InterceptedPacket struct {
387  	// IncomingCircuit contains the incoming channel and htlc id of the
388  	// packet.
389  	IncomingCircuit models.CircuitKey
390  
391  	// OutgoingChanID is the destination channel for this packet.
392  	OutgoingChanID lnwire.ShortChannelID
393  
394  	// Hash is the payment hash of the htlc.
395  	Hash lntypes.Hash
396  
397  	// OutgoingExpiry is the absolute block height at which the outgoing
398  	// htlc expires.
399  	OutgoingExpiry uint32
400  
401  	// OutgoingAmount is the amount to forward.
402  	OutgoingAmount lnwire.MilliSatoshi
403  
404  	// IncomingExpiry is the absolute block height at which the incoming
405  	// htlc expires.
406  	IncomingExpiry uint32
407  
408  	// IncomingAmount is the amount of the accepted htlc.
409  	IncomingAmount lnwire.MilliSatoshi
410  
411  	// InOnionCustomRecords are user-defined records in the custom type
412  	// range that were included in the payload.
413  	InOnionCustomRecords record.CustomSet
414  
415  	// OnionBlob is the onion packet for the next hop
416  	OnionBlob [lnwire.OnionPacketSize]byte
417  
418  	// InWireCustomRecords are user-defined p2p wire message records that
419  	// were defined by the peer that forwarded this HTLC to us.
420  	InWireCustomRecords lnwire.CustomRecords
421  
422  	// AutoFailHeight is the block height at which this intercept will be
423  	// failed back automatically.
424  	AutoFailHeight int32
425  }
426  
427  // InterceptedForward is passed to the ForwardInterceptor for every forwarded
428  // htlc. It contains all the information about the packet which accordingly
429  // the interceptor decides if to hold or not.
430  // In addition this interface allows a later resolution by calling either
431  // Resume, Settle or Fail.
432  type InterceptedForward interface {
433  	// Packet returns the intercepted packet.
434  	Packet() InterceptedPacket
435  
436  	// Resume notifies the intention to resume an existing hold forward. This
437  	// basically means the caller wants to resume with the default behavior for
438  	// this htlc which usually means forward it.
439  	Resume() error
440  
441  	// ResumeModified notifies the intention to resume an existing hold
442  	// forward with modified fields.
443  	ResumeModified(inAmountMsat,
444  		outAmountMsat fn.Option[lnwire.MilliSatoshi],
445  		outWireCustomRecords fn.Option[lnwire.CustomRecords]) error
446  
447  	// Settle notifies the intention to settle an existing hold
448  	// forward with a given preimage.
449  	Settle(lntypes.Preimage) error
450  
451  	// Fail notifies the intention to fail an existing hold forward with an
452  	// encrypted failure reason.
453  	Fail(reason []byte) error
454  
455  	// FailWithCode notifies the intention to fail an existing hold forward
456  	// with the specified failure code.
457  	FailWithCode(code lnwire.FailCode) error
458  }
459  
460  // htlcNotifier is an interface which represents the input side of the
461  // HtlcNotifier which htlc events are piped through. This interface is intended
462  // to allow for mocking of the htlcNotifier in tests, so is unexported because
463  // it is not needed outside of the htlcSwitch package.
464  type htlcNotifier interface {
465  	// NotifyForwardingEvent notifies the HtlcNotifier than a htlc has been
466  	// forwarded.
467  	NotifyForwardingEvent(key HtlcKey, info HtlcInfo,
468  		eventType HtlcEventType)
469  
470  	// NotifyLinkFailEvent notifies that a htlc has failed on our
471  	// incoming link. It takes an isReceive bool to differentiate between
472  	// our node's receives and forwards.
473  	NotifyLinkFailEvent(key HtlcKey, info HtlcInfo,
474  		eventType HtlcEventType, linkErr *LinkError, incoming bool)
475  
476  	// NotifyForwardingFailEvent notifies the HtlcNotifier that a htlc we
477  	// forwarded has failed down the line.
478  	NotifyForwardingFailEvent(key HtlcKey, eventType HtlcEventType)
479  
480  	// NotifySettleEvent notifies the HtlcNotifier that a htlc that we
481  	// committed to as part of a forward or a receive to our node has been
482  	// settled.
483  	NotifySettleEvent(key HtlcKey, preimage lntypes.Preimage,
484  		eventType HtlcEventType)
485  
486  	// NotifyFinalHtlcEvent notifies the HtlcNotifier that the final outcome
487  	// for an htlc has been determined.
488  	NotifyFinalHtlcEvent(key models.CircuitKey,
489  		info channeldb.FinalHtlcInfo)
490  }
491  
492  // AuxHtlcModifier is an interface that allows the sender to modify the outgoing
493  // HTLC of a payment by changing the amount or the wire message tlv records.
494  type AuxHtlcModifier interface {
495  	// ProduceHtlcExtraData is a function that, based on the previous extra
496  	// data blob of an HTLC, may produce a different blob or modify the
497  	// amount of bitcoin this htlc should carry.
498  	ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi,
499  		htlcCustomRecords lnwire.CustomRecords,
500  		peer route.Vertex) (lnwire.MilliSatoshi, lnwire.CustomRecords,
501  		error)
502  }
503  
504  // AuxTrafficShaper is an interface that allows the sender to determine if a
505  // payment should be carried by a channel based on the TLV records that may be
506  // present in the `update_add_htlc` message or the channel commitment itself.
507  type AuxTrafficShaper interface {
508  	AuxHtlcModifier
509  
510  	// ShouldHandleTraffic is called in order to check if the channel
511  	// identified by the provided channel ID may have external mechanisms
512  	// that would allow it to carry out the payment.
513  	ShouldHandleTraffic(cid lnwire.ShortChannelID,
514  		fundingBlob, htlcBlob fn.Option[tlv.Blob]) (bool, error)
515  
516  	// PaymentBandwidth returns the available bandwidth for a custom channel
517  	// decided by the given channel funding/commitment aux blob and HTLC
518  	// blob. A return value of 0 means there is no bandwidth available. To
519  	// find out if a channel is a custom channel that should be handled by
520  	// the traffic shaper, the ShouldHandleTraffic method should be called
521  	// first.
522  	PaymentBandwidth(fundingBlob, htlcBlob,
523  		commitmentBlob fn.Option[tlv.Blob],
524  		linkBandwidth, htlcAmt lnwire.MilliSatoshi,
525  		htlcView lnwallet.AuxHtlcView,
526  		peer route.Vertex) (lnwire.MilliSatoshi, error)
527  
528  	// IsCustomHTLC returns true if the HTLC carries the set of relevant
529  	// custom records to put it under the purview of the traffic shaper,
530  	// meaning that it's from a custom channel.
531  	IsCustomHTLC(htlcRecords lnwire.CustomRecords) bool
532  }