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

     1  package htlcswitch
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/davecgh/go-spew/spew"
     9  	"github.com/decred/dcrlnd/channeldb"
    10  	"github.com/decred/dcrlnd/htlcswitch/hop"
    11  	"github.com/decred/dcrlnd/kvdb"
    12  	"github.com/decred/dcrlnd/lnwire"
    13  	"github.com/go-errors/errors"
    14  )
    15  
    16  var (
    17  	// ErrCorruptedCircuitMap indicates that the on-disk bucketing structure
    18  	// has altered since the circuit map instance was initialized.
    19  	ErrCorruptedCircuitMap = errors.New("circuit map has been corrupted")
    20  
    21  	// ErrCircuitNotInHashIndex indicates that a particular circuit did not
    22  	// appear in the in-memory hash index.
    23  	ErrCircuitNotInHashIndex = errors.New("payment circuit not found in " +
    24  		"hash index")
    25  
    26  	// ErrUnknownCircuit signals that circuit could not be removed from the
    27  	// map because it was not found.
    28  	ErrUnknownCircuit = errors.New("unknown payment circuit")
    29  
    30  	// ErrCircuitClosing signals that an htlc has already closed this
    31  	// circuit in-memory.
    32  	ErrCircuitClosing = errors.New("circuit has already been closed")
    33  
    34  	// ErrDuplicateCircuit signals that this circuit was previously
    35  	// added.
    36  	ErrDuplicateCircuit = errors.New("duplicate circuit add")
    37  
    38  	// ErrUnknownKeystone signals that no circuit was found using the
    39  	// outgoing circuit key.
    40  	ErrUnknownKeystone = errors.New("unknown circuit keystone")
    41  
    42  	// ErrDuplicateKeystone signals that this circuit was previously
    43  	// assigned a keystone.
    44  	ErrDuplicateKeystone = errors.New("cannot add duplicate keystone")
    45  )
    46  
    47  // CircuitModifier is a common interface used by channel links to modify the
    48  // contents of the circuit map maintained by the switch.
    49  type CircuitModifier interface {
    50  	// OpenCircuits preemptively records a batch keystones that will mark
    51  	// currently pending circuits as open. These changes can be rolled back
    52  	// on restart if the outgoing Adds do not make it into a commitment
    53  	// txn.
    54  	OpenCircuits(...Keystone) error
    55  
    56  	// TrimOpenCircuits removes a channel's open channels with htlc indexes
    57  	// above `start`.
    58  	TrimOpenCircuits(chanID lnwire.ShortChannelID, start uint64) error
    59  
    60  	// DeleteCircuits removes the incoming circuit key to remove all
    61  	// persistent references to a circuit. Returns a ErrUnknownCircuit if
    62  	// any of the incoming keys are not known.
    63  	DeleteCircuits(inKeys ...CircuitKey) error
    64  }
    65  
    66  // CircuitLookup is a common interface used to lookup information that is stored
    67  // in the circuit map.
    68  type CircuitLookup interface {
    69  	// LookupCircuit queries the circuit map for the circuit identified by
    70  	// inKey.
    71  	LookupCircuit(inKey CircuitKey) *PaymentCircuit
    72  
    73  	// LookupOpenCircuit queries the circuit map for a circuit identified
    74  	// by its outgoing circuit key.
    75  	LookupOpenCircuit(outKey CircuitKey) *PaymentCircuit
    76  }
    77  
    78  // CircuitFwdActions represents the forwarding decision made by the circuit
    79  // map, and is returned from CommitCircuits. The sequence of circuits provided
    80  // to CommitCircuits is split into three sub-sequences, allowing the caller to
    81  // do an in-order scan, comparing the head of each subsequence, to determine
    82  // the decision made by the circuit map.
    83  type CircuitFwdActions struct {
    84  	// Adds is the subsequence of circuits that were successfully committed
    85  	// in the circuit map.
    86  	Adds []*PaymentCircuit
    87  
    88  	// Drops is the subsequence of circuits for which no action should be
    89  	// done.
    90  	Drops []*PaymentCircuit
    91  
    92  	// Fails is the subsequence of circuits that should be failed back by
    93  	// the calling link.
    94  	Fails []*PaymentCircuit
    95  }
    96  
    97  // CircuitMap is an interface for managing the construction and teardown of
    98  // payment circuits used by the switch.
    99  type CircuitMap interface {
   100  	CircuitModifier
   101  
   102  	CircuitLookup
   103  
   104  	// CommitCircuits attempts to add the given circuits to the circuit
   105  	// map. The list of circuits is split into three distinct
   106  	// sub-sequences, corresponding to adds, drops, and fails. Adds should
   107  	// be forwarded to the switch, while fails should be failed back
   108  	// locally within the calling link.
   109  	CommitCircuits(circuit ...*PaymentCircuit) (*CircuitFwdActions, error)
   110  
   111  	// CloseCircuit marks the circuit identified by `outKey` as closing
   112  	// in-memory, which prevents duplicate settles/fails from completing an
   113  	// open circuit twice.
   114  	CloseCircuit(outKey CircuitKey) (*PaymentCircuit, error)
   115  
   116  	// FailCircuit is used by locally failed HTLCs to mark the circuit
   117  	// identified by `inKey` as closing in-memory, which prevents duplicate
   118  	// settles/fails from being accepted for the same circuit.
   119  	FailCircuit(inKey CircuitKey) (*PaymentCircuit, error)
   120  
   121  	// LookupByPaymentHash queries the circuit map and returns all open
   122  	// circuits that use the given payment hash.
   123  	LookupByPaymentHash(hash [32]byte) []*PaymentCircuit
   124  
   125  	// NumPending returns the total number of active circuits added by
   126  	// CommitCircuits.
   127  	NumPending() int
   128  
   129  	// NumOpen returns the number of circuits with HTLCs that have been
   130  	// forwarded via an outgoing link.
   131  	NumOpen() int
   132  }
   133  
   134  var (
   135  	// circuitAddKey is the key used to retrieve the bucket containing
   136  	// payment circuits. A circuit records information about how to return
   137  	// a packet to the source link, potentially including an error
   138  	// encrypter for applying this hop's encryption to the payload in the
   139  	// reverse direction.
   140  	//
   141  	// Bucket hierarchy:
   142  	//
   143  	// circuitAddKey(root-bucket)
   144  	//     	|
   145  	//     	|-- <incoming-circuit-key>: <encoded bytes of PaymentCircuit>
   146  	//     	|-- <incoming-circuit-key>: <encoded bytes of PaymentCircuit>
   147  	//     	|
   148  	//     	...
   149  	//
   150  	circuitAddKey = []byte("circuit-adds")
   151  
   152  	// circuitKeystoneKey is used to retrieve the bucket containing circuit
   153  	// keystones, which are set in place once a forwarded packet is
   154  	// assigned an index on an outgoing commitment txn.
   155  	//
   156  	// Bucket hierarchy:
   157  	//
   158  	// circuitKeystoneKey(root-bucket)
   159  	//     	|
   160  	//     	|-- <outgoing-circuit-key>: <incoming-circuit-key>
   161  	//     	|-- <outgoing-circuit-key>: <incoming-circuit-key>
   162  	//     	|
   163  	//     	...
   164  	//
   165  	circuitKeystoneKey = []byte("circuit-keystones")
   166  )
   167  
   168  // circuitMap is a data structure that implements thread safe, persistent
   169  // storage of circuit routing information. The switch consults a circuit map to
   170  // determine where to forward returning HTLC update messages. Circuits are
   171  // always identifiable by their incoming CircuitKey, in addition to their
   172  // outgoing CircuitKey if the circuit is fully-opened.
   173  type circuitMap struct {
   174  	cfg *CircuitMapConfig
   175  
   176  	mtx sync.RWMutex
   177  
   178  	// pending is an in-memory mapping of all half payment circuits, and is
   179  	// kept in sync with the on-disk contents of the circuit map.
   180  	pending map[CircuitKey]*PaymentCircuit
   181  
   182  	// opened is an in-memory mapping of all full payment circuits, which
   183  	// is also synchronized with the persistent state of the circuit map.
   184  	opened map[CircuitKey]*PaymentCircuit
   185  
   186  	// closed is an in-memory set of circuits for which the switch has
   187  	// received a settle or fail. This precedes the actual deletion of a
   188  	// circuit from disk.
   189  	closed map[CircuitKey]struct{}
   190  
   191  	// hashIndex is a volatile index that facilitates fast queries by
   192  	// payment hash against the contents of circuits. This index can be
   193  	// reconstructed entirely from the set of persisted full circuits on
   194  	// startup.
   195  	hashIndex map[[32]byte]map[CircuitKey]struct{}
   196  }
   197  
   198  // CircuitMapConfig houses the critical interfaces and references necessary to
   199  // parameterize an instance of circuitMap.
   200  type CircuitMapConfig struct {
   201  	// DB provides the persistent storage engine for the circuit map.
   202  	DB kvdb.Backend
   203  
   204  	// FetchAllOpenChannels is a function that fetches all currently open
   205  	// channels from the channel database.
   206  	FetchAllOpenChannels func() ([]*channeldb.OpenChannel, error)
   207  
   208  	// FetchClosedChannels is a function that fetches all closed channels
   209  	// from the channel database.
   210  	FetchClosedChannels func(
   211  		pendingOnly bool) ([]*channeldb.ChannelCloseSummary, error)
   212  
   213  	// ExtractErrorEncrypter derives the shared secret used to encrypt
   214  	// errors from the obfuscator's ephemeral public key.
   215  	ExtractErrorEncrypter hop.ErrorEncrypterExtracter
   216  }
   217  
   218  // NewCircuitMap creates a new instance of the circuitMap.
   219  func NewCircuitMap(cfg *CircuitMapConfig) (CircuitMap, error) {
   220  	cm := &circuitMap{
   221  		cfg: cfg,
   222  	}
   223  
   224  	// Initialize the on-disk buckets used by the circuit map.
   225  	if err := cm.initBuckets(); err != nil {
   226  		return nil, err
   227  	}
   228  
   229  	// Delete old circuits and keystones of closed channels.
   230  	if err := cm.cleanClosedChannels(); err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	// Load any previously persisted circuit into back into memory.
   235  	if err := cm.restoreMemState(); err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	// Trim any keystones that were not committed in an outgoing commit txn.
   240  	//
   241  	// NOTE: This operation will be applied to the persistent state of all
   242  	// active channels. Therefore, it must be called before any links are
   243  	// created to avoid interfering with normal operation.
   244  	if err := cm.trimAllOpenCircuits(); err != nil {
   245  		return nil, err
   246  	}
   247  
   248  	return cm, nil
   249  }
   250  
   251  // initBuckets ensures that the primary buckets used by the circuit are
   252  // initialized so that we can assume their existence after startup.
   253  func (cm *circuitMap) initBuckets() error {
   254  	return kvdb.Update(cm.cfg.DB, func(tx kvdb.RwTx) error {
   255  		_, err := tx.CreateTopLevelBucket(circuitKeystoneKey)
   256  		if err != nil {
   257  			return err
   258  		}
   259  
   260  		_, err = tx.CreateTopLevelBucket(circuitAddKey)
   261  		return err
   262  	}, func() {})
   263  }
   264  
   265  // cleanClosedChannels deletes all circuits and keystones related to closed
   266  // channels. It first reads all the closed channels and caches the ShortChanIDs
   267  // into a map for fast lookup. Then it iterates the circuit bucket and keystone
   268  // bucket and deletes items whose ChanID matches the ShortChanID.
   269  //
   270  // NOTE: this operation can also be built into restoreMemState since the latter
   271  // already opens and iterates the two root buckets, circuitAddKey and
   272  // circuitKeystoneKey. Depending on the size of the buckets, this marginal gain
   273  // may be worth investigating. Atm, for clarity, this operation is wrapped into
   274  // its own function.
   275  func (cm *circuitMap) cleanClosedChannels() error {
   276  	log.Infof("Cleaning circuits from disk for closed channels")
   277  
   278  	// closedChanIDSet stores the short channel IDs for closed channels.
   279  	closedChanIDSet := make(map[lnwire.ShortChannelID]struct{})
   280  
   281  	// circuitKeySet stores the incoming circuit keys of the payment
   282  	// circuits that need to be deleted.
   283  	circuitKeySet := make(map[CircuitKey]struct{})
   284  
   285  	// keystoneKeySet stores the outgoing keys of the keystones that need
   286  	// to be deleted.
   287  	keystoneKeySet := make(map[CircuitKey]struct{})
   288  
   289  	// isClosedChannel is a helper closure that returns a bool indicating
   290  	// the chanID belongs to a closed channel.
   291  	isClosedChannel := func(chanID lnwire.ShortChannelID) bool {
   292  		// Skip if the channel ID is zero value. This has the effect
   293  		// that a zero value incoming or outgoing key will never be
   294  		// matched and its corresponding circuits or keystones are not
   295  		// deleted.
   296  		if chanID.ToUint64() == 0 {
   297  			return false
   298  		}
   299  
   300  		_, ok := closedChanIDSet[chanID]
   301  		return ok
   302  	}
   303  
   304  	// Find closed channels and cache their ShortChannelIDs into a map.
   305  	// This map will be used for looking up relative circuits and keystones.
   306  	closedChannels, err := cm.cfg.FetchClosedChannels(false)
   307  	if err != nil {
   308  		return err
   309  	}
   310  
   311  	for _, closedChannel := range closedChannels {
   312  		// Skip if the channel close is pending.
   313  		if closedChannel.IsPending {
   314  			continue
   315  		}
   316  
   317  		closedChanIDSet[closedChannel.ShortChanID] = struct{}{}
   318  	}
   319  
   320  	log.Debugf("Found %v closed channels", len(closedChanIDSet))
   321  
   322  	// Exit early if there are no closed channels.
   323  	if len(closedChanIDSet) == 0 {
   324  		log.Infof("Finished cleaning: no closed channels found, " +
   325  			"no actions taken.",
   326  		)
   327  		return nil
   328  	}
   329  
   330  	// Find the payment circuits and keystones that need to be deleted.
   331  	if err := kvdb.View(cm.cfg.DB, func(tx kvdb.RTx) error {
   332  		circuitBkt := tx.ReadBucket(circuitAddKey)
   333  		if circuitBkt == nil {
   334  			return ErrCorruptedCircuitMap
   335  		}
   336  		keystoneBkt := tx.ReadBucket(circuitKeystoneKey)
   337  		if keystoneBkt == nil {
   338  			return ErrCorruptedCircuitMap
   339  		}
   340  
   341  		// If a circuit's incoming/outgoing key prefix matches the
   342  		// ShortChanID, it will be deleted. However, if the ShortChanID
   343  		// of the incoming key is zero, the circuit will be kept as it
   344  		// indicates a locally initiated payment.
   345  		if err := circuitBkt.ForEach(func(_, v []byte) error {
   346  			circuit, err := cm.decodeCircuit(v)
   347  			if err != nil {
   348  				return err
   349  			}
   350  
   351  			// Check if the incoming channel ID can be found in the
   352  			// closed channel ID map.
   353  			if !isClosedChannel(circuit.Incoming.ChanID) {
   354  				return nil
   355  			}
   356  
   357  			circuitKeySet[circuit.Incoming] = struct{}{}
   358  
   359  			return nil
   360  		}); err != nil {
   361  			return err
   362  		}
   363  
   364  		// If a keystone's InKey or OutKey matches the short channel id
   365  		// in the closed channel ID map, it will be deleted.
   366  		err := keystoneBkt.ForEach(func(k, v []byte) error {
   367  			var (
   368  				inKey  CircuitKey
   369  				outKey CircuitKey
   370  			)
   371  
   372  			// Decode the incoming and outgoing circuit keys.
   373  			if err := inKey.SetBytes(v); err != nil {
   374  				return err
   375  			}
   376  			if err := outKey.SetBytes(k); err != nil {
   377  				return err
   378  			}
   379  
   380  			// Check if the incoming channel ID can be found in the
   381  			// closed channel ID map.
   382  			if isClosedChannel(inKey.ChanID) {
   383  				// If the incoming channel is closed, we can
   384  				// skip checking on outgoing channel ID because
   385  				// this keystone will be deleted.
   386  				keystoneKeySet[outKey] = struct{}{}
   387  
   388  				// Technically the incoming keys found in
   389  				// keystone bucket should be a subset of
   390  				// circuit bucket. So a previous loop should
   391  				// have this inKey put inside circuitAddKey map
   392  				// already. We do this again to be sure the
   393  				// circuits are properly cleaned. Even this
   394  				// inKey doesn't exist in circuit bucket, we
   395  				// are fine as db deletion is a noop.
   396  				circuitKeySet[inKey] = struct{}{}
   397  				return nil
   398  			}
   399  
   400  			// Check if the outgoing channel ID can be found in the
   401  			// closed channel ID map. Notice that we need to store
   402  			// the outgoing key because it's used for db query.
   403  			if isClosedChannel(outKey.ChanID) {
   404  				keystoneKeySet[outKey] = struct{}{}
   405  
   406  				// Also update circuitKeySet to mark the
   407  				// payment circuit needs to be deleted.
   408  				circuitKeySet[inKey] = struct{}{}
   409  			}
   410  
   411  			return nil
   412  		})
   413  		return err
   414  
   415  	}, func() {
   416  		// Reset the sets.
   417  		circuitKeySet = make(map[CircuitKey]struct{})
   418  		keystoneKeySet = make(map[CircuitKey]struct{})
   419  	}); err != nil {
   420  		return err
   421  	}
   422  
   423  	log.Debugf("To be deleted: num_circuits=%v, num_keystones=%v",
   424  		len(circuitKeySet), len(keystoneKeySet),
   425  	)
   426  
   427  	numCircuitsDeleted := 0
   428  	numKeystonesDeleted := 0
   429  
   430  	// Delete all the circuits and keystones for closed channels.
   431  	if err := kvdb.Update(cm.cfg.DB, func(tx kvdb.RwTx) error {
   432  		circuitBkt := tx.ReadWriteBucket(circuitAddKey)
   433  		if circuitBkt == nil {
   434  			return ErrCorruptedCircuitMap
   435  		}
   436  		keystoneBkt := tx.ReadWriteBucket(circuitKeystoneKey)
   437  		if keystoneBkt == nil {
   438  			return ErrCorruptedCircuitMap
   439  		}
   440  
   441  		// Delete the ciruit.
   442  		for inKey := range circuitKeySet {
   443  			if err := circuitBkt.Delete(inKey.Bytes()); err != nil {
   444  				return err
   445  			}
   446  
   447  			numCircuitsDeleted++
   448  		}
   449  
   450  		// Delete the keystone using the outgoing key.
   451  		for outKey := range keystoneKeySet {
   452  			err := keystoneBkt.Delete(outKey.Bytes())
   453  			if err != nil {
   454  				return err
   455  			}
   456  
   457  			numKeystonesDeleted++
   458  		}
   459  
   460  		return nil
   461  	}, func() {}); err != nil {
   462  		numCircuitsDeleted = 0
   463  		numKeystonesDeleted = 0
   464  		return err
   465  	}
   466  
   467  	log.Infof("Finished cleaning: num_closed_channel=%v, "+
   468  		"num_circuits=%v, num_keystone=%v",
   469  		len(closedChannels), numCircuitsDeleted, numKeystonesDeleted,
   470  	)
   471  
   472  	return nil
   473  }
   474  
   475  // restoreMemState loads the contents of the half circuit and full circuit
   476  // buckets from disk and reconstructs the in-memory representation of the
   477  // circuit map. Afterwards, the state of the hash index is reconstructed using
   478  // the recovered set of full circuits. This method will also remove any stray
   479  // keystones, which are those that appear fully-opened, but have no pending
   480  // circuit related to the intended incoming link.
   481  func (cm *circuitMap) restoreMemState() error {
   482  	log.Infof("Restoring in-memory circuit state from disk")
   483  
   484  	var (
   485  		opened  map[CircuitKey]*PaymentCircuit
   486  		pending map[CircuitKey]*PaymentCircuit
   487  	)
   488  
   489  	if err := kvdb.Update(cm.cfg.DB, func(tx kvdb.RwTx) error {
   490  		// Restore any of the circuits persisted in the circuit bucket
   491  		// back into memory.
   492  		circuitBkt := tx.ReadWriteBucket(circuitAddKey)
   493  		if circuitBkt == nil {
   494  			return ErrCorruptedCircuitMap
   495  		}
   496  
   497  		if err := circuitBkt.ForEach(func(_, v []byte) error {
   498  			circuit, err := cm.decodeCircuit(v)
   499  			if err != nil {
   500  				return err
   501  			}
   502  
   503  			circuit.LoadedFromDisk = true
   504  			pending[circuit.Incoming] = circuit
   505  
   506  			return nil
   507  		}); err != nil {
   508  			return err
   509  		}
   510  
   511  		// Furthermore, load the keystone bucket and resurrect the
   512  		// keystones used in any open circuits.
   513  		keystoneBkt := tx.ReadWriteBucket(circuitKeystoneKey)
   514  		if keystoneBkt == nil {
   515  			return ErrCorruptedCircuitMap
   516  		}
   517  
   518  		var strayKeystones []Keystone
   519  		if err := keystoneBkt.ForEach(func(k, v []byte) error {
   520  			var (
   521  				inKey  CircuitKey
   522  				outKey = &CircuitKey{}
   523  			)
   524  
   525  			// Decode the incoming and outgoing circuit keys.
   526  			if err := inKey.SetBytes(v); err != nil {
   527  				return err
   528  			}
   529  			if err := outKey.SetBytes(k); err != nil {
   530  				return err
   531  			}
   532  
   533  			// Retrieve the pending circuit, set its keystone, then
   534  			// add it to the opened map.
   535  			circuit, ok := pending[inKey]
   536  			if ok {
   537  				circuit.Outgoing = outKey
   538  				opened[*outKey] = circuit
   539  			} else {
   540  				strayKeystones = append(strayKeystones, Keystone{
   541  					InKey:  inKey,
   542  					OutKey: *outKey,
   543  				})
   544  			}
   545  
   546  			return nil
   547  		}); err != nil {
   548  			return err
   549  		}
   550  
   551  		// If any stray keystones were found, we'll proceed to prune
   552  		// them from the circuit map's persistent storage. This may
   553  		// manifest on older nodes that had updated channels before
   554  		// their short channel id was set properly. We believe this
   555  		// issue has been fixed, though this will allow older nodes to
   556  		// recover without additional intervention.
   557  		for _, strayKeystone := range strayKeystones {
   558  			// As a precaution, we will only cleanup keystones
   559  			// related to locally-initiated payments. If a
   560  			// documented case of stray keystones emerges for
   561  			// forwarded payments, this check should be removed, but
   562  			// with extreme caution.
   563  			if strayKeystone.OutKey.ChanID != hop.Source {
   564  				continue
   565  			}
   566  
   567  			log.Infof("Removing stray keystone: %v", strayKeystone)
   568  			err := keystoneBkt.Delete(strayKeystone.OutKey.Bytes())
   569  			if err != nil {
   570  				return err
   571  			}
   572  		}
   573  
   574  		return nil
   575  
   576  	}, func() {
   577  		opened = make(map[CircuitKey]*PaymentCircuit)
   578  		pending = make(map[CircuitKey]*PaymentCircuit)
   579  	}); err != nil {
   580  		return err
   581  	}
   582  
   583  	cm.pending = pending
   584  	cm.opened = opened
   585  	cm.closed = make(map[CircuitKey]struct{})
   586  
   587  	log.Infof("Payment circuits loaded: num_pending=%v, num_open=%v",
   588  		len(pending), len(opened))
   589  
   590  	// Finally, reconstruct the hash index by running through our set of
   591  	// open circuits.
   592  	cm.hashIndex = make(map[[32]byte]map[CircuitKey]struct{})
   593  	for _, circuit := range opened {
   594  		cm.addCircuitToHashIndex(circuit)
   595  	}
   596  
   597  	return nil
   598  }
   599  
   600  // decodeCircuit reconstructs an in-memory payment circuit from a byte slice.
   601  // The byte slice is assumed to have been generated by the circuit's Encode
   602  // method. If the decoding is successful, the onion obfuscator will be
   603  // reextracted, since it is not stored in plaintext on disk.
   604  func (cm *circuitMap) decodeCircuit(v []byte) (*PaymentCircuit, error) {
   605  	var circuit = &PaymentCircuit{}
   606  
   607  	circuitReader := bytes.NewReader(v)
   608  	if err := circuit.Decode(circuitReader); err != nil {
   609  		return nil, err
   610  	}
   611  
   612  	// If the error encrypter is nil, this is locally-source payment so
   613  	// there is no encrypter.
   614  	if circuit.ErrorEncrypter == nil {
   615  		return circuit, nil
   616  	}
   617  
   618  	// Otherwise, we need to reextract the encrypter, so that the shared
   619  	// secret is rederived from what was decoded.
   620  	err := circuit.ErrorEncrypter.Reextract(
   621  		cm.cfg.ExtractErrorEncrypter,
   622  	)
   623  	if err != nil {
   624  		return nil, err
   625  	}
   626  
   627  	return circuit, nil
   628  }
   629  
   630  // trimAllOpenCircuits reads the set of active channels from disk and trims
   631  // keystones for any non-pending channels using the next unallocated htlc index.
   632  // This method is intended to be called on startup. Each link will also trim
   633  // it's own circuits upon startup.
   634  //
   635  // NOTE: This operation will be applied to the persistent state of all active
   636  // channels. Therefore, it must be called before any links are created to avoid
   637  // interfering with normal operation.
   638  func (cm *circuitMap) trimAllOpenCircuits() error {
   639  	activeChannels, err := cm.cfg.FetchAllOpenChannels()
   640  	if err != nil {
   641  		return err
   642  	}
   643  
   644  	for _, activeChannel := range activeChannels {
   645  		if activeChannel.IsPending {
   646  			continue
   647  		}
   648  
   649  		// First, skip any channels that have not been assigned their
   650  		// final channel identifier, otherwise we would try to trim
   651  		// htlcs belonging to the all-zero, hop.Source ID.
   652  		chanID := activeChannel.ShortChanID()
   653  		if chanID == hop.Source {
   654  			continue
   655  		}
   656  
   657  		// Next, retrieve the next unallocated htlc index, which bounds
   658  		// the cutoff of confirmed htlc indexes.
   659  		start, err := activeChannel.NextLocalHtlcIndex()
   660  		if err != nil {
   661  			return err
   662  		}
   663  
   664  		// Finally, remove all pending circuits above at or above the
   665  		// next unallocated local htlc indexes. This has the effect of
   666  		// reverting any circuits that have either not been locked in,
   667  		// or had not been included in a pending commitment.
   668  		err = cm.TrimOpenCircuits(chanID, start)
   669  		if err != nil {
   670  			return err
   671  		}
   672  	}
   673  
   674  	return nil
   675  }
   676  
   677  // TrimOpenCircuits removes a channel's keystones above the short chan id's
   678  // highest committed htlc index. This has the effect of returning those
   679  // circuits to a half-open state. Since opening of circuits is done in advance
   680  // of actually committing the Add htlcs into a commitment txn, this allows
   681  // circuits to be opened preemptively, since we can roll them back after any
   682  // failures.
   683  func (cm *circuitMap) TrimOpenCircuits(chanID lnwire.ShortChannelID,
   684  	start uint64) error {
   685  
   686  	log.Infof("Trimming open circuits for chan_id=%v, start_htlc_id=%v",
   687  		chanID, start)
   688  
   689  	var trimmedOutKeys []CircuitKey
   690  
   691  	// Scan forward from the last unacked htlc id, stopping as soon as we
   692  	// don't find any more. Outgoing htlc id's must be assigned in order,
   693  	// so there should never be disjoint segments of keystones to trim.
   694  	cm.mtx.Lock()
   695  	for i := start; ; i++ {
   696  		outKey := CircuitKey{
   697  			ChanID: chanID,
   698  			HtlcID: i,
   699  		}
   700  
   701  		circuit, ok := cm.opened[outKey]
   702  		if !ok {
   703  			break
   704  		}
   705  
   706  		circuit.Outgoing = nil
   707  		delete(cm.opened, outKey)
   708  		trimmedOutKeys = append(trimmedOutKeys, outKey)
   709  		cm.removeCircuitFromHashIndex(circuit)
   710  	}
   711  	cm.mtx.Unlock()
   712  
   713  	if len(trimmedOutKeys) == 0 {
   714  		return nil
   715  	}
   716  
   717  	return kvdb.Update(cm.cfg.DB, func(tx kvdb.RwTx) error {
   718  		keystoneBkt := tx.ReadWriteBucket(circuitKeystoneKey)
   719  		if keystoneBkt == nil {
   720  			return ErrCorruptedCircuitMap
   721  		}
   722  
   723  		for _, outKey := range trimmedOutKeys {
   724  			err := keystoneBkt.Delete(outKey.Bytes())
   725  			if err != nil {
   726  				return err
   727  			}
   728  		}
   729  
   730  		return nil
   731  	}, func() {})
   732  }
   733  
   734  // LookupCircuit queries the circuit map for the circuit identified by its
   735  // incoming circuit key. Returns nil if there is no such circuit.
   736  func (cm *circuitMap) LookupCircuit(inKey CircuitKey) *PaymentCircuit {
   737  	cm.mtx.RLock()
   738  	defer cm.mtx.RUnlock()
   739  
   740  	return cm.pending[inKey]
   741  }
   742  
   743  // LookupOpenCircuit searches for the circuit identified by its outgoing circuit
   744  // key.
   745  func (cm *circuitMap) LookupOpenCircuit(outKey CircuitKey) *PaymentCircuit {
   746  	cm.mtx.RLock()
   747  	defer cm.mtx.RUnlock()
   748  
   749  	return cm.opened[outKey]
   750  }
   751  
   752  // LookupByPaymentHash looks up and returns any payment circuits with a given
   753  // payment hash.
   754  func (cm *circuitMap) LookupByPaymentHash(hash [32]byte) []*PaymentCircuit {
   755  	cm.mtx.RLock()
   756  	defer cm.mtx.RUnlock()
   757  
   758  	var circuits []*PaymentCircuit
   759  	if circuitSet, ok := cm.hashIndex[hash]; ok {
   760  		// Iterate over the outgoing circuit keys found with this hash,
   761  		// and retrieve the circuit from the opened map.
   762  		circuits = make([]*PaymentCircuit, 0, len(circuitSet))
   763  		for key := range circuitSet {
   764  			if circuit, ok := cm.opened[key]; ok {
   765  				circuits = append(circuits, circuit)
   766  			}
   767  		}
   768  	}
   769  
   770  	return circuits
   771  }
   772  
   773  // CommitCircuits accepts any number of circuits and persistently adds them to
   774  // the switch's circuit map. The method returns a list of circuits that had not
   775  // been seen prior by the switch. A link should only forward HTLCs corresponding
   776  // to the returned circuits to the switch.
   777  //
   778  // NOTE: This method uses batched writes to improve performance, gains will only
   779  // be realized if it is called concurrently from separate goroutines.
   780  func (cm *circuitMap) CommitCircuits(circuits ...*PaymentCircuit) (
   781  	*CircuitFwdActions, error) {
   782  
   783  	inKeys := make([]CircuitKey, 0, len(circuits))
   784  	for _, circuit := range circuits {
   785  		inKeys = append(inKeys, circuit.Incoming)
   786  	}
   787  
   788  	log.Tracef("Committing fresh circuits: %v", newLogClosure(func() string {
   789  		return spew.Sdump(inKeys)
   790  	}))
   791  
   792  	actions := &CircuitFwdActions{}
   793  
   794  	// If an empty list was passed, return early to avoid grabbing the lock.
   795  	if len(circuits) == 0 {
   796  		return actions, nil
   797  	}
   798  
   799  	// First, we reconcile the provided circuits with our set of pending
   800  	// circuits to construct a set of new circuits that need to be written
   801  	// to disk. The circuit's pointer is stored so that we only permit this
   802  	// exact circuit to be forwarded through the switch. If a circuit is
   803  	// already pending, the htlc will be reforwarded by the switch.
   804  	//
   805  	// NOTE: We track an additional addFails subsequence, which permits us
   806  	// to fail back all packets that weren't dropped if we encounter an
   807  	// error when committing the circuits.
   808  	cm.mtx.Lock()
   809  	var adds, drops, fails, addFails []*PaymentCircuit
   810  	for _, circuit := range circuits {
   811  		inKey := circuit.InKey()
   812  		if foundCircuit, ok := cm.pending[inKey]; ok {
   813  			switch {
   814  
   815  			// This circuit has a keystone, it's waiting for a
   816  			// response from the remote peer on the outgoing link.
   817  			// Drop it like it's hot, ensure duplicates get caught.
   818  			case foundCircuit.HasKeystone():
   819  				drops = append(drops, circuit)
   820  
   821  			// If no keystone is set and the switch has not been
   822  			// restarted, the corresponding packet should still be
   823  			// in the outgoing link's mailbox. It will be delivered
   824  			// if it comes online before the switch goes down.
   825  			//
   826  			// NOTE: Dropping here prevents a flapping, incoming
   827  			// link from failing a duplicate add while it is still
   828  			// in the server's memory mailboxes.
   829  			case !foundCircuit.LoadedFromDisk:
   830  				drops = append(drops, circuit)
   831  
   832  			// Otherwise, the in-mem packet has been lost due to a
   833  			// restart. It is now safe to send back a failure along
   834  			// the incoming link. The incoming link should be able
   835  			// detect and ignore duplicate packets of this type.
   836  			default:
   837  				fails = append(fails, circuit)
   838  				addFails = append(addFails, circuit)
   839  			}
   840  
   841  			continue
   842  		}
   843  
   844  		cm.pending[inKey] = circuit
   845  		adds = append(adds, circuit)
   846  		addFails = append(addFails, circuit)
   847  	}
   848  	cm.mtx.Unlock()
   849  
   850  	// If all circuits are dropped or failed, we are done.
   851  	if len(adds) == 0 {
   852  		actions.Drops = drops
   853  		actions.Fails = fails
   854  		return actions, nil
   855  	}
   856  
   857  	// Now, optimistically serialize the circuits to add.
   858  	var bs = make([]bytes.Buffer, len(adds))
   859  	for i, circuit := range adds {
   860  		if err := circuit.Encode(&bs[i]); err != nil {
   861  			actions.Drops = drops
   862  			actions.Fails = addFails
   863  			return actions, err
   864  		}
   865  	}
   866  
   867  	// Write the entire batch of circuits to the persistent circuit bucket
   868  	// using bbolt's Batch write. This method must be called from multiple,
   869  	// distinct goroutines to have any impact on performance.
   870  	err := kvdb.Batch(cm.cfg.DB, func(tx kvdb.RwTx) error {
   871  		circuitBkt := tx.ReadWriteBucket(circuitAddKey)
   872  		if circuitBkt == nil {
   873  			return ErrCorruptedCircuitMap
   874  		}
   875  
   876  		for i, circuit := range adds {
   877  			inKeyBytes := circuit.InKey().Bytes()
   878  			circuitBytes := bs[i].Bytes()
   879  
   880  			err := circuitBkt.Put(inKeyBytes, circuitBytes)
   881  			if err != nil {
   882  				return err
   883  			}
   884  		}
   885  
   886  		return nil
   887  	})
   888  
   889  	// Return if the write succeeded.
   890  	if err == nil {
   891  		actions.Adds = adds
   892  		actions.Drops = drops
   893  		actions.Fails = fails
   894  		return actions, nil
   895  	}
   896  
   897  	// Otherwise, rollback the circuits added to the pending set if the
   898  	// write failed.
   899  	cm.mtx.Lock()
   900  	for _, circuit := range adds {
   901  		delete(cm.pending, circuit.InKey())
   902  	}
   903  	cm.mtx.Unlock()
   904  
   905  	// Since our write failed, we will return the dropped packets and mark
   906  	// all other circuits as failed.
   907  	actions.Drops = drops
   908  	actions.Fails = addFails
   909  
   910  	return actions, err
   911  }
   912  
   913  // Keystone is a tuple binding an incoming and outgoing CircuitKey. Keystones
   914  // are preemptively written by an outgoing link before signing a new commitment
   915  // state, and cements which HTLCs we are awaiting a response from a remote
   916  // peer.
   917  type Keystone struct {
   918  	InKey  CircuitKey
   919  	OutKey CircuitKey
   920  }
   921  
   922  // String returns a human readable description of the Keystone.
   923  func (k *Keystone) String() string {
   924  	return fmt.Sprintf("%s --> %s", k.InKey, k.OutKey)
   925  }
   926  
   927  // OpenCircuits sets the outgoing circuit key for the circuit identified by
   928  // inKey, persistently marking the circuit as opened. After the changes have
   929  // been persisted, the circuit map's in-memory indexes are updated so that this
   930  // circuit can be queried using LookupByKeystone or LookupByPaymentHash.
   931  func (cm *circuitMap) OpenCircuits(keystones ...Keystone) error {
   932  	if len(keystones) == 0 {
   933  		return nil
   934  	}
   935  
   936  	log.Tracef("Opening finalized circuits: %v", newLogClosure(func() string {
   937  		return spew.Sdump(keystones)
   938  	}))
   939  
   940  	// Check that all keystones correspond to committed-but-unopened
   941  	// circuits.
   942  	cm.mtx.RLock()
   943  	openedCircuits := make([]*PaymentCircuit, 0, len(keystones))
   944  	for _, ks := range keystones {
   945  		if _, ok := cm.opened[ks.OutKey]; ok {
   946  			cm.mtx.RUnlock()
   947  			return ErrDuplicateKeystone
   948  		}
   949  
   950  		circuit, ok := cm.pending[ks.InKey]
   951  		if !ok {
   952  			cm.mtx.RUnlock()
   953  			return ErrUnknownCircuit
   954  		}
   955  
   956  		openedCircuits = append(openedCircuits, circuit)
   957  	}
   958  	cm.mtx.RUnlock()
   959  
   960  	err := kvdb.Update(cm.cfg.DB, func(tx kvdb.RwTx) error {
   961  		// Now, load the circuit bucket to which we will write the
   962  		// already serialized circuit.
   963  		keystoneBkt := tx.ReadWriteBucket(circuitKeystoneKey)
   964  		if keystoneBkt == nil {
   965  			return ErrCorruptedCircuitMap
   966  		}
   967  
   968  		for _, ks := range keystones {
   969  			outBytes := ks.OutKey.Bytes()
   970  			inBytes := ks.InKey.Bytes()
   971  			err := keystoneBkt.Put(outBytes, inBytes)
   972  			if err != nil {
   973  				return err
   974  			}
   975  		}
   976  
   977  		return nil
   978  	}, func() {})
   979  
   980  	if err != nil {
   981  		return err
   982  	}
   983  
   984  	cm.mtx.Lock()
   985  	for i, circuit := range openedCircuits {
   986  		ks := keystones[i]
   987  
   988  		// Since our persistent operation was successful, we can now
   989  		// modify the in memory representations. Set the outgoing
   990  		// circuit key on our pending circuit, add the same circuit to
   991  		// set of opened circuits, and add this circuit to the hash
   992  		// index.
   993  		circuit.Outgoing = &CircuitKey{}
   994  		*circuit.Outgoing = ks.OutKey
   995  
   996  		cm.opened[ks.OutKey] = circuit
   997  		cm.addCircuitToHashIndex(circuit)
   998  	}
   999  	cm.mtx.Unlock()
  1000  
  1001  	return nil
  1002  }
  1003  
  1004  // addCirciutToHashIndex inserts a circuit into the circuit map's hash index, so
  1005  // that it can be queried using LookupByPaymentHash.
  1006  func (cm *circuitMap) addCircuitToHashIndex(c *PaymentCircuit) {
  1007  	if _, ok := cm.hashIndex[c.PaymentHash]; !ok {
  1008  		cm.hashIndex[c.PaymentHash] = make(map[CircuitKey]struct{})
  1009  	}
  1010  	cm.hashIndex[c.PaymentHash][c.OutKey()] = struct{}{}
  1011  }
  1012  
  1013  // FailCircuit marks the circuit identified by `inKey` as closing in-memory,
  1014  // which prevents duplicate settles/fails from completing an open circuit twice.
  1015  func (cm *circuitMap) FailCircuit(inKey CircuitKey) (*PaymentCircuit, error) {
  1016  
  1017  	cm.mtx.Lock()
  1018  	defer cm.mtx.Unlock()
  1019  
  1020  	circuit, ok := cm.pending[inKey]
  1021  	if !ok {
  1022  		return nil, ErrUnknownCircuit
  1023  	}
  1024  
  1025  	_, ok = cm.closed[inKey]
  1026  	if ok {
  1027  		return nil, ErrCircuitClosing
  1028  	}
  1029  
  1030  	cm.closed[inKey] = struct{}{}
  1031  
  1032  	return circuit, nil
  1033  }
  1034  
  1035  // CloseCircuit marks the circuit identified by `outKey` as closing in-memory,
  1036  // which prevents duplicate settles/fails from completing an open
  1037  // circuit twice.
  1038  func (cm *circuitMap) CloseCircuit(outKey CircuitKey) (*PaymentCircuit, error) {
  1039  
  1040  	cm.mtx.Lock()
  1041  	defer cm.mtx.Unlock()
  1042  
  1043  	circuit, ok := cm.opened[outKey]
  1044  	if !ok {
  1045  		return nil, ErrUnknownCircuit
  1046  	}
  1047  
  1048  	_, ok = cm.closed[circuit.Incoming]
  1049  	if ok {
  1050  		return nil, ErrCircuitClosing
  1051  	}
  1052  
  1053  	cm.closed[circuit.Incoming] = struct{}{}
  1054  
  1055  	return circuit, nil
  1056  }
  1057  
  1058  // DeleteCircuits destroys the target circuits by removing them from the circuit
  1059  // map, additionally removing the circuits' keystones if any HTLCs were
  1060  // forwarded through an outgoing link. The circuits should be identified by its
  1061  // incoming circuit key. If a given circuit is not found in the circuit map, it
  1062  // will be ignored from the query. This would typically indicate that the
  1063  // circuit was already cleaned up at a different point in time.
  1064  func (cm *circuitMap) DeleteCircuits(inKeys ...CircuitKey) error {
  1065  
  1066  	log.Tracef("Deleting resolved circuits: %v", newLogClosure(func() string {
  1067  		return spew.Sdump(inKeys)
  1068  	}))
  1069  
  1070  	var (
  1071  		closingCircuits = make(map[CircuitKey]struct{})
  1072  		removedCircuits = make(map[CircuitKey]*PaymentCircuit)
  1073  	)
  1074  
  1075  	cm.mtx.Lock()
  1076  	// Remove any references to the circuits from memory, keeping track of
  1077  	// which circuits were removed, and which ones had been marked closed.
  1078  	// This can be used to restore these entries later if the persistent
  1079  	// removal fails.
  1080  	for _, inKey := range inKeys {
  1081  		circuit, ok := cm.pending[inKey]
  1082  		if !ok {
  1083  			continue
  1084  		}
  1085  		delete(cm.pending, inKey)
  1086  
  1087  		if _, ok := cm.closed[inKey]; ok {
  1088  			closingCircuits[inKey] = struct{}{}
  1089  			delete(cm.closed, inKey)
  1090  		}
  1091  
  1092  		if circuit.HasKeystone() {
  1093  			delete(cm.opened, circuit.OutKey())
  1094  			cm.removeCircuitFromHashIndex(circuit)
  1095  		}
  1096  
  1097  		removedCircuits[inKey] = circuit
  1098  	}
  1099  	cm.mtx.Unlock()
  1100  
  1101  	err := kvdb.Batch(cm.cfg.DB, func(tx kvdb.RwTx) error {
  1102  		for _, circuit := range removedCircuits {
  1103  			// If this htlc made it to an outgoing link, load the
  1104  			// keystone bucket from which we will remove the
  1105  			// outgoing circuit key.
  1106  			if circuit.HasKeystone() {
  1107  				keystoneBkt := tx.ReadWriteBucket(circuitKeystoneKey)
  1108  				if keystoneBkt == nil {
  1109  					return ErrCorruptedCircuitMap
  1110  				}
  1111  
  1112  				outKey := circuit.OutKey()
  1113  
  1114  				err := keystoneBkt.Delete(outKey.Bytes())
  1115  				if err != nil {
  1116  					return err
  1117  				}
  1118  			}
  1119  
  1120  			// Remove the circuit itself based on the incoming
  1121  			// circuit key.
  1122  			circuitBkt := tx.ReadWriteBucket(circuitAddKey)
  1123  			if circuitBkt == nil {
  1124  				return ErrCorruptedCircuitMap
  1125  			}
  1126  
  1127  			inKey := circuit.InKey()
  1128  			if err := circuitBkt.Delete(inKey.Bytes()); err != nil {
  1129  				return err
  1130  			}
  1131  		}
  1132  
  1133  		return nil
  1134  	})
  1135  
  1136  	// Return if the write succeeded.
  1137  	if err == nil {
  1138  		return nil
  1139  	}
  1140  
  1141  	// If the persistent changes failed, restore the circuit map to it's
  1142  	// previous state.
  1143  	cm.mtx.Lock()
  1144  	for inKey, circuit := range removedCircuits {
  1145  		cm.pending[inKey] = circuit
  1146  
  1147  		if _, ok := closingCircuits[inKey]; ok {
  1148  			cm.closed[inKey] = struct{}{}
  1149  		}
  1150  
  1151  		if circuit.HasKeystone() {
  1152  			cm.opened[circuit.OutKey()] = circuit
  1153  			cm.addCircuitToHashIndex(circuit)
  1154  		}
  1155  	}
  1156  	cm.mtx.Unlock()
  1157  
  1158  	return err
  1159  }
  1160  
  1161  // removeCircuitFromHashIndex removes the given circuit from the hash index,
  1162  // pruning any unnecessary memory optimistically.
  1163  func (cm *circuitMap) removeCircuitFromHashIndex(c *PaymentCircuit) {
  1164  	// Locate bucket containing this circuit's payment hashes.
  1165  	circuitsWithHash, ok := cm.hashIndex[c.PaymentHash]
  1166  	if !ok {
  1167  		return
  1168  	}
  1169  
  1170  	outKey := c.OutKey()
  1171  
  1172  	// Remove this circuit from the set of circuitsWithHash.
  1173  	delete(circuitsWithHash, outKey)
  1174  
  1175  	// Prune the payment hash bucket if no other entries remain.
  1176  	if len(circuitsWithHash) == 0 {
  1177  		delete(cm.hashIndex, c.PaymentHash)
  1178  	}
  1179  }
  1180  
  1181  // NumPending returns the number of active circuits added to the circuit map.
  1182  func (cm *circuitMap) NumPending() int {
  1183  	cm.mtx.RLock()
  1184  	defer cm.mtx.RUnlock()
  1185  
  1186  	return len(cm.pending)
  1187  }
  1188  
  1189  // NumOpen returns the number of circuits that have been opened by way of
  1190  // setting their keystones. This is the number of HTLCs that are waiting for a
  1191  // settle/fail response from a remote peer.
  1192  func (cm *circuitMap) NumOpen() int {
  1193  	cm.mtx.RLock()
  1194  	defer cm.mtx.RUnlock()
  1195  
  1196  	return len(cm.opened)
  1197  }