mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 09:48:19 +01:00
Merge pull request #8950 from ProofOfKeags/refactor/lnwallet-channel-move-only
[NANO]: Move definitions into their own file
This commit is contained in:
commit
72a36da9c6
4 changed files with 481 additions and 462 deletions
|
@ -2,7 +2,6 @@ package lnwallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"container/list"
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -168,220 +167,6 @@ func (e *ErrCommitSyncLocalDataLoss) Error() string {
|
||||||
// payments requested by the wallet/daemon.
|
// payments requested by the wallet/daemon.
|
||||||
type PaymentHash [32]byte
|
type PaymentHash [32]byte
|
||||||
|
|
||||||
// updateType is the exact type of an entry within the shared HTLC log.
|
|
||||||
type updateType uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Add is an update type that adds a new HTLC entry into the log.
|
|
||||||
// Either side can add a new pending HTLC by adding a new Add entry
|
|
||||||
// into their update log.
|
|
||||||
Add updateType = iota
|
|
||||||
|
|
||||||
// Fail is an update type which removes a prior HTLC entry from the
|
|
||||||
// log. Adding a Fail entry to one's log will modify the _remote_
|
|
||||||
// party's update log once a new commitment view has been evaluated
|
|
||||||
// which contains the Fail entry.
|
|
||||||
Fail
|
|
||||||
|
|
||||||
// MalformedFail is an update type which removes a prior HTLC entry
|
|
||||||
// from the log. Adding a MalformedFail entry to one's log will modify
|
|
||||||
// the _remote_ party's update log once a new commitment view has been
|
|
||||||
// evaluated which contains the MalformedFail entry. The difference
|
|
||||||
// from Fail type lie in the different data we have to store.
|
|
||||||
MalformedFail
|
|
||||||
|
|
||||||
// Settle is an update type which settles a prior HTLC crediting the
|
|
||||||
// balance of the receiving node. Adding a Settle entry to a log will
|
|
||||||
// result in the settle entry being removed on the log as well as the
|
|
||||||
// original add entry from the remote party's log after the next state
|
|
||||||
// transition.
|
|
||||||
Settle
|
|
||||||
|
|
||||||
// FeeUpdate is an update type sent by the channel initiator that
|
|
||||||
// updates the fee rate used when signing the commitment transaction.
|
|
||||||
FeeUpdate
|
|
||||||
)
|
|
||||||
|
|
||||||
// String returns a human readable string that uniquely identifies the target
|
|
||||||
// update type.
|
|
||||||
func (u updateType) String() string {
|
|
||||||
switch u {
|
|
||||||
case Add:
|
|
||||||
return "Add"
|
|
||||||
case Fail:
|
|
||||||
return "Fail"
|
|
||||||
case MalformedFail:
|
|
||||||
return "MalformedFail"
|
|
||||||
case Settle:
|
|
||||||
return "Settle"
|
|
||||||
case FeeUpdate:
|
|
||||||
return "FeeUpdate"
|
|
||||||
default:
|
|
||||||
return "<unknown type>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PaymentDescriptor represents a commitment state update which either adds,
|
|
||||||
// settles, or removes an HTLC. PaymentDescriptors encapsulate all necessary
|
|
||||||
// metadata w.r.t to an HTLC, and additional data pairing a settle message to
|
|
||||||
// the original added HTLC.
|
|
||||||
//
|
|
||||||
// TODO(roasbeef): LogEntry interface??
|
|
||||||
// - need to separate attrs for cancel/add/settle/feeupdate
|
|
||||||
type PaymentDescriptor struct {
|
|
||||||
// RHash is the payment hash for this HTLC. The HTLC can be settled iff
|
|
||||||
// the preimage to this hash is presented.
|
|
||||||
RHash PaymentHash
|
|
||||||
|
|
||||||
// RPreimage is the preimage that settles the HTLC pointed to within the
|
|
||||||
// log by the ParentIndex.
|
|
||||||
RPreimage PaymentHash
|
|
||||||
|
|
||||||
// Timeout is the absolute timeout in blocks, after which this HTLC
|
|
||||||
// expires.
|
|
||||||
Timeout uint32
|
|
||||||
|
|
||||||
// Amount is the HTLC amount in milli-satoshis.
|
|
||||||
Amount lnwire.MilliSatoshi
|
|
||||||
|
|
||||||
// LogIndex is the log entry number that his HTLC update has within the
|
|
||||||
// log. Depending on if IsIncoming is true, this is either an entry the
|
|
||||||
// remote party added, or one that we added locally.
|
|
||||||
LogIndex uint64
|
|
||||||
|
|
||||||
// HtlcIndex is the index within the main update log for this HTLC.
|
|
||||||
// Entries within the log of type Add will have this field populated,
|
|
||||||
// as other entries will point to the entry via this counter.
|
|
||||||
//
|
|
||||||
// NOTE: This field will only be populate if EntryType is Add.
|
|
||||||
HtlcIndex uint64
|
|
||||||
|
|
||||||
// ParentIndex is the HTLC index of the entry that this update settles or
|
|
||||||
// times out.
|
|
||||||
//
|
|
||||||
// NOTE: This field will only be populate if EntryType is Fail or
|
|
||||||
// Settle.
|
|
||||||
ParentIndex uint64
|
|
||||||
|
|
||||||
// SourceRef points to an Add update in a forwarding package owned by
|
|
||||||
// this channel.
|
|
||||||
//
|
|
||||||
// NOTE: This field will only be populated if EntryType is Fail or
|
|
||||||
// Settle.
|
|
||||||
SourceRef *channeldb.AddRef
|
|
||||||
|
|
||||||
// DestRef points to a Fail/Settle update in another link's forwarding
|
|
||||||
// package.
|
|
||||||
//
|
|
||||||
// NOTE: This field will only be populated if EntryType is Fail or
|
|
||||||
// Settle, and the forwarded Add successfully included in an outgoing
|
|
||||||
// link's commitment txn.
|
|
||||||
DestRef *channeldb.SettleFailRef
|
|
||||||
|
|
||||||
// OpenCircuitKey references the incoming Chan/HTLC ID of an Add HTLC
|
|
||||||
// packet delivered by the switch.
|
|
||||||
//
|
|
||||||
// NOTE: This field is only populated for payment descriptors in the
|
|
||||||
// *local* update log, and if the Add packet was delivered by the
|
|
||||||
// switch.
|
|
||||||
OpenCircuitKey *models.CircuitKey
|
|
||||||
|
|
||||||
// ClosedCircuitKey references the incoming Chan/HTLC ID of the Add HTLC
|
|
||||||
// that opened the circuit.
|
|
||||||
//
|
|
||||||
// NOTE: This field is only populated for payment descriptors in the
|
|
||||||
// *local* update log, and if settle/fails have a committed circuit in
|
|
||||||
// the circuit map.
|
|
||||||
ClosedCircuitKey *models.CircuitKey
|
|
||||||
|
|
||||||
// localOutputIndex is the output index of this HTLc output in the
|
|
||||||
// commitment transaction of the local node.
|
|
||||||
//
|
|
||||||
// NOTE: If the output is dust from the PoV of the local commitment
|
|
||||||
// chain, then this value will be -1.
|
|
||||||
localOutputIndex int32
|
|
||||||
|
|
||||||
// remoteOutputIndex is the output index of this HTLC output in the
|
|
||||||
// commitment transaction of the remote node.
|
|
||||||
//
|
|
||||||
// NOTE: If the output is dust from the PoV of the remote commitment
|
|
||||||
// chain, then this value will be -1.
|
|
||||||
remoteOutputIndex int32
|
|
||||||
|
|
||||||
// sig is the signature for the second-level HTLC transaction that
|
|
||||||
// spends the version of this HTLC on the commitment transaction of the
|
|
||||||
// local node. This signature is generated by the remote node and
|
|
||||||
// stored by the local node in the case that local node needs to
|
|
||||||
// broadcast their commitment transaction.
|
|
||||||
sig input.Signature
|
|
||||||
|
|
||||||
// addCommitHeight[Remote|Local] encodes the height of the commitment
|
|
||||||
// which included this HTLC on either the remote or local commitment
|
|
||||||
// chain. This value is used to determine when an HTLC is fully
|
|
||||||
// "locked-in".
|
|
||||||
addCommitHeightRemote uint64
|
|
||||||
addCommitHeightLocal uint64
|
|
||||||
|
|
||||||
// removeCommitHeight[Remote|Local] encodes the height of the
|
|
||||||
// commitment which removed the parent pointer of this
|
|
||||||
// PaymentDescriptor either due to a timeout or a settle. Once both
|
|
||||||
// these heights are below the tail of both chains, the log entries can
|
|
||||||
// safely be removed.
|
|
||||||
removeCommitHeightRemote uint64
|
|
||||||
removeCommitHeightLocal uint64
|
|
||||||
|
|
||||||
// OnionBlob is an opaque blob which is used to complete multi-hop
|
|
||||||
// routing.
|
|
||||||
//
|
|
||||||
// NOTE: Populated only on add payment descriptor entry types.
|
|
||||||
OnionBlob []byte
|
|
||||||
|
|
||||||
// ShaOnionBlob is a sha of the onion blob.
|
|
||||||
//
|
|
||||||
// NOTE: Populated only in payment descriptor with MalformedFail type.
|
|
||||||
ShaOnionBlob [sha256.Size]byte
|
|
||||||
|
|
||||||
// FailReason stores the reason why a particular payment was canceled.
|
|
||||||
//
|
|
||||||
// NOTE: Populate only in fail payment descriptor entry types.
|
|
||||||
FailReason []byte
|
|
||||||
|
|
||||||
// FailCode stores the code why a particular payment was canceled.
|
|
||||||
//
|
|
||||||
// NOTE: Populated only in payment descriptor with MalformedFail type.
|
|
||||||
FailCode lnwire.FailCode
|
|
||||||
|
|
||||||
// [our|their|]PkScript are the raw public key scripts that encodes the
|
|
||||||
// redemption rules for this particular HTLC. These fields will only be
|
|
||||||
// populated iff the EntryType of this PaymentDescriptor is Add.
|
|
||||||
// ourPkScript is the ourPkScript from the context of our local
|
|
||||||
// commitment chain. theirPkScript is the latest pkScript from the
|
|
||||||
// context of the remote commitment chain.
|
|
||||||
//
|
|
||||||
// NOTE: These values may change within the logs themselves, however,
|
|
||||||
// they'll stay consistent within the commitment chain entries
|
|
||||||
// themselves.
|
|
||||||
ourPkScript []byte
|
|
||||||
ourWitnessScript []byte
|
|
||||||
theirPkScript []byte
|
|
||||||
theirWitnessScript []byte
|
|
||||||
|
|
||||||
// EntryType denotes the exact type of the PaymentDescriptor. In the
|
|
||||||
// case of a Timeout, or Settle type, then the Parent field will point
|
|
||||||
// into the log to the HTLC being modified.
|
|
||||||
EntryType updateType
|
|
||||||
|
|
||||||
// isForwarded denotes if an incoming HTLC has been forwarded to any
|
|
||||||
// possible upstream peers in the route.
|
|
||||||
isForwarded bool
|
|
||||||
|
|
||||||
// BlindingPoint is an optional ephemeral key used in route blinding.
|
|
||||||
// This value is set for nodes that are relaying payments inside of a
|
|
||||||
// blinded route (ie, not the introduction node) from update_add_htlc's
|
|
||||||
// TLVs.
|
|
||||||
BlindingPoint lnwire.BlindingPointRecord
|
|
||||||
}
|
|
||||||
|
|
||||||
// PayDescsFromRemoteLogUpdates converts a slice of LogUpdates received from the
|
// PayDescsFromRemoteLogUpdates converts a slice of LogUpdates received from the
|
||||||
// remote peer into PaymentDescriptors to inform a link's forwarding decisions.
|
// remote peer into PaymentDescriptors to inform a link's forwarding decisions.
|
||||||
//
|
//
|
||||||
|
@ -983,253 +768,6 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
|
||||||
return commit, nil
|
return commit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// commitmentChain represents a chain of unrevoked commitments. The tail of the
|
|
||||||
// chain is the latest fully signed, yet unrevoked commitment. Two chains are
|
|
||||||
// tracked, one for the local node, and another for the remote node. New
|
|
||||||
// commitments we create locally extend the remote node's chain, and vice
|
|
||||||
// versa. Commitment chains are allowed to grow to a bounded length, after
|
|
||||||
// which the tail needs to be "dropped" before new commitments can be received.
|
|
||||||
// The tail is "dropped" when the owner of the chain sends a revocation for the
|
|
||||||
// previous tail.
|
|
||||||
type commitmentChain struct {
|
|
||||||
// commitments is a linked list of commitments to new states. New
|
|
||||||
// commitments are added to the end of the chain with increase height.
|
|
||||||
// Once a commitment transaction is revoked, the tail is incremented,
|
|
||||||
// freeing up the revocation window for new commitments.
|
|
||||||
commitments *list.List
|
|
||||||
}
|
|
||||||
|
|
||||||
// newCommitmentChain creates a new commitment chain.
|
|
||||||
func newCommitmentChain() *commitmentChain {
|
|
||||||
return &commitmentChain{
|
|
||||||
commitments: list.New(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// addCommitment extends the commitment chain by a single commitment. This
|
|
||||||
// added commitment represents a state update proposed by either party. Once
|
|
||||||
// the commitment prior to this commitment is revoked, the commitment becomes
|
|
||||||
// the new defacto state within the channel.
|
|
||||||
func (s *commitmentChain) addCommitment(c *commitment) {
|
|
||||||
s.commitments.PushBack(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// advanceTail reduces the length of the commitment chain by one. The tail of
|
|
||||||
// the chain should be advanced once a revocation for the lowest unrevoked
|
|
||||||
// commitment in the chain is received.
|
|
||||||
func (s *commitmentChain) advanceTail() {
|
|
||||||
s.commitments.Remove(s.commitments.Front())
|
|
||||||
}
|
|
||||||
|
|
||||||
// tip returns the latest commitment added to the chain.
|
|
||||||
func (s *commitmentChain) tip() *commitment {
|
|
||||||
return s.commitments.Back().Value.(*commitment)
|
|
||||||
}
|
|
||||||
|
|
||||||
// tail returns the lowest unrevoked commitment transaction in the chain.
|
|
||||||
func (s *commitmentChain) tail() *commitment {
|
|
||||||
return s.commitments.Front().Value.(*commitment)
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasUnackedCommitment returns true if the commitment chain has more than one
|
|
||||||
// entry. The tail of the commitment chain has been ACKed by revoking all prior
|
|
||||||
// commitments, but any subsequent commitments have not yet been ACKed.
|
|
||||||
func (s *commitmentChain) hasUnackedCommitment() bool {
|
|
||||||
return s.commitments.Front() != s.commitments.Back()
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateLog is an append-only log that stores updates to a node's commitment
|
|
||||||
// chain. This structure can be seen as the "mempool" within Lightning where
|
|
||||||
// changes are stored before they're committed to the chain. Once an entry has
|
|
||||||
// been committed in both the local and remote commitment chain, then it can be
|
|
||||||
// removed from this log.
|
|
||||||
//
|
|
||||||
// TODO(roasbeef): create lightning package, move commitment and update to
|
|
||||||
// package?
|
|
||||||
// - also move state machine, separate from lnwallet package
|
|
||||||
// - possible embed updateLog within commitmentChain.
|
|
||||||
type updateLog struct {
|
|
||||||
// logIndex is a monotonically increasing integer that tracks the total
|
|
||||||
// number of update entries ever applied to the log. When sending new
|
|
||||||
// commitment states, we include all updates up to this index.
|
|
||||||
logIndex uint64
|
|
||||||
|
|
||||||
// htlcCounter is a monotonically increasing integer that tracks the
|
|
||||||
// total number of offered HTLC's by the owner of this update log,
|
|
||||||
// hence the `Add` update type. We use a distinct index for this
|
|
||||||
// purpose, as update's that remove entries from the log will be
|
|
||||||
// indexed using this counter.
|
|
||||||
htlcCounter uint64
|
|
||||||
|
|
||||||
// List is the updatelog itself, we embed this value so updateLog has
|
|
||||||
// access to all the method of a list.List.
|
|
||||||
*list.List
|
|
||||||
|
|
||||||
// updateIndex maps a `logIndex` to a particular update entry. It
|
|
||||||
// deals with the four update types:
|
|
||||||
// `Fail|MalformedFail|Settle|FeeUpdate`
|
|
||||||
updateIndex map[uint64]*list.Element
|
|
||||||
|
|
||||||
// htlcIndex maps a `htlcCounter` to an offered HTLC entry, hence the
|
|
||||||
// `Add` update.
|
|
||||||
htlcIndex map[uint64]*list.Element
|
|
||||||
|
|
||||||
// modifiedHtlcs is a set that keeps track of all the current modified
|
|
||||||
// htlcs, hence update types `Fail|MalformedFail|Settle`. A modified
|
|
||||||
// HTLC is one that's present in the log, and has as a pending fail or
|
|
||||||
// settle that's attempting to consume it.
|
|
||||||
modifiedHtlcs map[uint64]struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newUpdateLog creates a new updateLog instance.
|
|
||||||
func newUpdateLog(logIndex, htlcCounter uint64) *updateLog {
|
|
||||||
return &updateLog{
|
|
||||||
List: list.New(),
|
|
||||||
updateIndex: make(map[uint64]*list.Element),
|
|
||||||
htlcIndex: make(map[uint64]*list.Element),
|
|
||||||
logIndex: logIndex,
|
|
||||||
htlcCounter: htlcCounter,
|
|
||||||
modifiedHtlcs: make(map[uint64]struct{}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// restoreHtlc will "restore" a prior HTLC to the updateLog. We say restore as
|
|
||||||
// this method is intended to be used when re-covering a prior commitment
|
|
||||||
// state. This function differs from appendHtlc in that it won't increment
|
|
||||||
// either of log's counters. If the HTLC is already present, then it is
|
|
||||||
// ignored.
|
|
||||||
func (u *updateLog) restoreHtlc(pd *PaymentDescriptor) {
|
|
||||||
if _, ok := u.htlcIndex[pd.HtlcIndex]; ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
u.htlcIndex[pd.HtlcIndex] = u.PushBack(pd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendUpdate appends a new update to the tip of the updateLog. The entry is
|
|
||||||
// also added to index accordingly.
|
|
||||||
func (u *updateLog) appendUpdate(pd *PaymentDescriptor) {
|
|
||||||
u.updateIndex[u.logIndex] = u.PushBack(pd)
|
|
||||||
u.logIndex++
|
|
||||||
}
|
|
||||||
|
|
||||||
// restoreUpdate appends a new update to the tip of the updateLog. The entry is
|
|
||||||
// also added to index accordingly. This function differs from appendUpdate in
|
|
||||||
// that it won't increment the log index counter.
|
|
||||||
func (u *updateLog) restoreUpdate(pd *PaymentDescriptor) {
|
|
||||||
u.updateIndex[pd.LogIndex] = u.PushBack(pd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendHtlc appends a new HTLC offer to the tip of the update log. The entry
|
|
||||||
// is also added to the offer index accordingly.
|
|
||||||
func (u *updateLog) appendHtlc(pd *PaymentDescriptor) {
|
|
||||||
u.htlcIndex[u.htlcCounter] = u.PushBack(pd)
|
|
||||||
u.htlcCounter++
|
|
||||||
|
|
||||||
u.logIndex++
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookupHtlc attempts to look up an offered HTLC according to its offer
|
|
||||||
// index. If the entry isn't found, then a nil pointer is returned.
|
|
||||||
func (u *updateLog) lookupHtlc(i uint64) *PaymentDescriptor {
|
|
||||||
htlc, ok := u.htlcIndex[i]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return htlc.Value.(*PaymentDescriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove attempts to remove an entry from the update log. If the entry is
|
|
||||||
// found, then the entry will be removed from the update log and index.
|
|
||||||
func (u *updateLog) removeUpdate(i uint64) {
|
|
||||||
entry := u.updateIndex[i]
|
|
||||||
u.Remove(entry)
|
|
||||||
delete(u.updateIndex, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeHtlc attempts to remove an HTLC offer form the update log. If the
|
|
||||||
// entry is found, then the entry will be removed from both the main log and
|
|
||||||
// the offer index.
|
|
||||||
func (u *updateLog) removeHtlc(i uint64) {
|
|
||||||
entry := u.htlcIndex[i]
|
|
||||||
u.Remove(entry)
|
|
||||||
delete(u.htlcIndex, i)
|
|
||||||
|
|
||||||
delete(u.modifiedHtlcs, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// htlcHasModification returns true if the HTLC identified by the passed index
|
|
||||||
// has a pending modification within the log.
|
|
||||||
func (u *updateLog) htlcHasModification(i uint64) bool {
|
|
||||||
_, o := u.modifiedHtlcs[i]
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// markHtlcModified marks an HTLC as modified based on its HTLC index. After a
|
|
||||||
// call to this method, htlcHasModification will return true until the HTLC is
|
|
||||||
// removed.
|
|
||||||
func (u *updateLog) markHtlcModified(i uint64) {
|
|
||||||
u.modifiedHtlcs[i] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// compactLogs performs garbage collection within the log removing HTLCs which
|
|
||||||
// have been removed from the point-of-view of the tail of both chains. The
|
|
||||||
// entries which timeout/settle HTLCs are also removed.
|
|
||||||
func compactLogs(ourLog, theirLog *updateLog,
|
|
||||||
localChainTail, remoteChainTail uint64) {
|
|
||||||
|
|
||||||
compactLog := func(logA, logB *updateLog) {
|
|
||||||
var nextA *list.Element
|
|
||||||
for e := logA.Front(); e != nil; e = nextA {
|
|
||||||
// Assign next iteration element at top of loop because
|
|
||||||
// we may remove the current element from the list,
|
|
||||||
// which can change the iterated sequence.
|
|
||||||
nextA = e.Next()
|
|
||||||
|
|
||||||
htlc := e.Value.(*PaymentDescriptor)
|
|
||||||
|
|
||||||
// We skip Adds, as they will be removed along with the
|
|
||||||
// fail/settles below.
|
|
||||||
if htlc.EntryType == Add {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the HTLC hasn't yet been removed from either
|
|
||||||
// chain, the skip it.
|
|
||||||
if htlc.removeCommitHeightRemote == 0 ||
|
|
||||||
htlc.removeCommitHeightLocal == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise if the height of the tail of both chains
|
|
||||||
// is at least the height in which the HTLC was
|
|
||||||
// removed, then evict the settle/timeout entry along
|
|
||||||
// with the original add entry.
|
|
||||||
if remoteChainTail >= htlc.removeCommitHeightRemote &&
|
|
||||||
localChainTail >= htlc.removeCommitHeightLocal {
|
|
||||||
|
|
||||||
// Fee updates have no parent htlcs, so we only
|
|
||||||
// remove the update itself.
|
|
||||||
if htlc.EntryType == FeeUpdate {
|
|
||||||
logA.removeUpdate(htlc.LogIndex)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// The other types (fail/settle) do have a
|
|
||||||
// parent HTLC, so we'll remove that HTLC from
|
|
||||||
// the other log.
|
|
||||||
logA.removeUpdate(htlc.LogIndex)
|
|
||||||
logB.removeHtlc(htlc.ParentIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compactLog(ourLog, theirLog)
|
|
||||||
compactLog(theirLog, ourLog)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LightningChannel implements the state machine which corresponds to the
|
// LightningChannel implements the state machine which corresponds to the
|
||||||
// current commitment protocol wire spec. The state machine implemented allows
|
// current commitment protocol wire spec. The state machine implemented allows
|
||||||
// for asynchronous fully desynchronized, batched+pipelined updates to
|
// for asynchronous fully desynchronized, batched+pipelined updates to
|
||||||
|
|
60
lnwallet/commitment_chain.go
Normal file
60
lnwallet/commitment_chain.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package lnwallet
|
||||||
|
|
||||||
|
import "container/list"
|
||||||
|
|
||||||
|
// commitmentChain represents a chain of unrevoked commitments. The tail of the
|
||||||
|
// chain is the latest fully signed, yet unrevoked commitment. Two chains are
|
||||||
|
// tracked, one for the local node, and another for the remote node. New
|
||||||
|
// commitments we create locally extend the remote node's chain, and vice
|
||||||
|
// versa. Commitment chains are allowed to grow to a bounded length, after
|
||||||
|
// which the tail needs to be "dropped" before new commitments can be received.
|
||||||
|
// The tail is "dropped" when the owner of the chain sends a revocation for the
|
||||||
|
// previous tail.
|
||||||
|
type commitmentChain struct {
|
||||||
|
// commitments is a linked list of commitments to new states. New
|
||||||
|
// commitments are added to the end of the chain with increase height.
|
||||||
|
// Once a commitment transaction is revoked, the tail is incremented,
|
||||||
|
// freeing up the revocation window for new commitments.
|
||||||
|
commitments *list.List
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCommitmentChain creates a new commitment chain.
|
||||||
|
func newCommitmentChain() *commitmentChain {
|
||||||
|
return &commitmentChain{
|
||||||
|
commitments: list.New(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addCommitment extends the commitment chain by a single commitment. This
|
||||||
|
// added commitment represents a state update proposed by either party. Once
|
||||||
|
// the commitment prior to this commitment is revoked, the commitment becomes
|
||||||
|
// the new defacto state within the channel.
|
||||||
|
func (s *commitmentChain) addCommitment(c *commitment) {
|
||||||
|
s.commitments.PushBack(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// advanceTail reduces the length of the commitment chain by one. The tail of
|
||||||
|
// the chain should be advanced once a revocation for the lowest unrevoked
|
||||||
|
// commitment in the chain is received.
|
||||||
|
func (s *commitmentChain) advanceTail() {
|
||||||
|
s.commitments.Remove(s.commitments.Front())
|
||||||
|
}
|
||||||
|
|
||||||
|
// tip returns the latest commitment added to the chain.
|
||||||
|
func (s *commitmentChain) tip() *commitment {
|
||||||
|
//nolint:forcetypeassert
|
||||||
|
return s.commitments.Back().Value.(*commitment)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tail returns the lowest unrevoked commitment transaction in the chain.
|
||||||
|
func (s *commitmentChain) tail() *commitment {
|
||||||
|
//nolint:forcetypeassert
|
||||||
|
return s.commitments.Front().Value.(*commitment)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasUnackedCommitment returns true if the commitment chain has more than one
|
||||||
|
// entry. The tail of the commitment chain has been ACKed by revoking all prior
|
||||||
|
// commitments, but any subsequent commitments have not yet been ACKed.
|
||||||
|
func (s *commitmentChain) hasUnackedCommitment() bool {
|
||||||
|
return s.commitments.Front() != s.commitments.Back()
|
||||||
|
}
|
224
lnwallet/payment_descriptor.go
Normal file
224
lnwallet/payment_descriptor.go
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
package lnwallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||||
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
)
|
||||||
|
|
||||||
|
// updateType is the exact type of an entry within the shared HTLC log.
|
||||||
|
type updateType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Add is an update type that adds a new HTLC entry into the log.
|
||||||
|
// Either side can add a new pending HTLC by adding a new Add entry
|
||||||
|
// into their update log.
|
||||||
|
Add updateType = iota
|
||||||
|
|
||||||
|
// Fail is an update type which removes a prior HTLC entry from the
|
||||||
|
// log. Adding a Fail entry to one's log will modify the _remote_
|
||||||
|
// party's update log once a new commitment view has been evaluated
|
||||||
|
// which contains the Fail entry.
|
||||||
|
Fail
|
||||||
|
|
||||||
|
// MalformedFail is an update type which removes a prior HTLC entry
|
||||||
|
// from the log. Adding a MalformedFail entry to one's log will modify
|
||||||
|
// the _remote_ party's update log once a new commitment view has been
|
||||||
|
// evaluated which contains the MalformedFail entry. The difference
|
||||||
|
// from Fail type lie in the different data we have to store.
|
||||||
|
MalformedFail
|
||||||
|
|
||||||
|
// Settle is an update type which settles a prior HTLC crediting the
|
||||||
|
// balance of the receiving node. Adding a Settle entry to a log will
|
||||||
|
// result in the settle entry being removed on the log as well as the
|
||||||
|
// original add entry from the remote party's log after the next state
|
||||||
|
// transition.
|
||||||
|
Settle
|
||||||
|
|
||||||
|
// FeeUpdate is an update type sent by the channel initiator that
|
||||||
|
// updates the fee rate used when signing the commitment transaction.
|
||||||
|
FeeUpdate
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns a human readable string that uniquely identifies the target
|
||||||
|
// update type.
|
||||||
|
func (u updateType) String() string {
|
||||||
|
switch u {
|
||||||
|
case Add:
|
||||||
|
return "Add"
|
||||||
|
case Fail:
|
||||||
|
return "Fail"
|
||||||
|
case MalformedFail:
|
||||||
|
return "MalformedFail"
|
||||||
|
case Settle:
|
||||||
|
return "Settle"
|
||||||
|
case FeeUpdate:
|
||||||
|
return "FeeUpdate"
|
||||||
|
default:
|
||||||
|
return "<unknown type>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentDescriptor represents a commitment state update which either adds,
|
||||||
|
// settles, or removes an HTLC. PaymentDescriptors encapsulate all necessary
|
||||||
|
// metadata w.r.t to an HTLC, and additional data pairing a settle message to
|
||||||
|
// the original added HTLC.
|
||||||
|
//
|
||||||
|
// TODO(roasbeef): LogEntry interface??
|
||||||
|
// - need to separate attrs for cancel/add/settle/feeupdate
|
||||||
|
type PaymentDescriptor struct {
|
||||||
|
// RHash is the payment hash for this HTLC. The HTLC can be settled iff
|
||||||
|
// the preimage to this hash is presented.
|
||||||
|
RHash PaymentHash
|
||||||
|
|
||||||
|
// RPreimage is the preimage that settles the HTLC pointed to within the
|
||||||
|
// log by the ParentIndex.
|
||||||
|
RPreimage PaymentHash
|
||||||
|
|
||||||
|
// Timeout is the absolute timeout in blocks, after which this HTLC
|
||||||
|
// expires.
|
||||||
|
Timeout uint32
|
||||||
|
|
||||||
|
// Amount is the HTLC amount in milli-satoshis.
|
||||||
|
Amount lnwire.MilliSatoshi
|
||||||
|
|
||||||
|
// LogIndex is the log entry number that his HTLC update has within the
|
||||||
|
// log. Depending on if IsIncoming is true, this is either an entry the
|
||||||
|
// remote party added, or one that we added locally.
|
||||||
|
LogIndex uint64
|
||||||
|
|
||||||
|
// HtlcIndex is the index within the main update log for this HTLC.
|
||||||
|
// Entries within the log of type Add will have this field populated,
|
||||||
|
// as other entries will point to the entry via this counter.
|
||||||
|
//
|
||||||
|
// NOTE: This field will only be populate if EntryType is Add.
|
||||||
|
HtlcIndex uint64
|
||||||
|
|
||||||
|
// ParentIndex is the HTLC index of the entry that this update settles
|
||||||
|
// or times out.
|
||||||
|
//
|
||||||
|
// NOTE: This field will only be populate if EntryType is Fail or
|
||||||
|
// Settle.
|
||||||
|
ParentIndex uint64
|
||||||
|
|
||||||
|
// SourceRef points to an Add update in a forwarding package owned by
|
||||||
|
// this channel.
|
||||||
|
//
|
||||||
|
// NOTE: This field will only be populated if EntryType is Fail or
|
||||||
|
// Settle.
|
||||||
|
SourceRef *channeldb.AddRef
|
||||||
|
|
||||||
|
// DestRef points to a Fail/Settle update in another link's forwarding
|
||||||
|
// package.
|
||||||
|
//
|
||||||
|
// NOTE: This field will only be populated if EntryType is Fail or
|
||||||
|
// Settle, and the forwarded Add successfully included in an outgoing
|
||||||
|
// link's commitment txn.
|
||||||
|
DestRef *channeldb.SettleFailRef
|
||||||
|
|
||||||
|
// OpenCircuitKey references the incoming Chan/HTLC ID of an Add HTLC
|
||||||
|
// packet delivered by the switch.
|
||||||
|
//
|
||||||
|
// NOTE: This field is only populated for payment descriptors in the
|
||||||
|
// *local* update log, and if the Add packet was delivered by the
|
||||||
|
// switch.
|
||||||
|
OpenCircuitKey *models.CircuitKey
|
||||||
|
|
||||||
|
// ClosedCircuitKey references the incoming Chan/HTLC ID of the Add HTLC
|
||||||
|
// that opened the circuit.
|
||||||
|
//
|
||||||
|
// NOTE: This field is only populated for payment descriptors in the
|
||||||
|
// *local* update log, and if settle/fails have a committed circuit in
|
||||||
|
// the circuit map.
|
||||||
|
ClosedCircuitKey *models.CircuitKey
|
||||||
|
|
||||||
|
// localOutputIndex is the output index of this HTLc output in the
|
||||||
|
// commitment transaction of the local node.
|
||||||
|
//
|
||||||
|
// NOTE: If the output is dust from the PoV of the local commitment
|
||||||
|
// chain, then this value will be -1.
|
||||||
|
localOutputIndex int32
|
||||||
|
|
||||||
|
// remoteOutputIndex is the output index of this HTLC output in the
|
||||||
|
// commitment transaction of the remote node.
|
||||||
|
//
|
||||||
|
// NOTE: If the output is dust from the PoV of the remote commitment
|
||||||
|
// chain, then this value will be -1.
|
||||||
|
remoteOutputIndex int32
|
||||||
|
|
||||||
|
// sig is the signature for the second-level HTLC transaction that
|
||||||
|
// spends the version of this HTLC on the commitment transaction of the
|
||||||
|
// local node. This signature is generated by the remote node and
|
||||||
|
// stored by the local node in the case that local node needs to
|
||||||
|
// broadcast their commitment transaction.
|
||||||
|
sig input.Signature
|
||||||
|
|
||||||
|
// addCommitHeight[Remote|Local] encodes the height of the commitment
|
||||||
|
// which included this HTLC on either the remote or local commitment
|
||||||
|
// chain. This value is used to determine when an HTLC is fully
|
||||||
|
// "locked-in".
|
||||||
|
addCommitHeightRemote uint64
|
||||||
|
addCommitHeightLocal uint64
|
||||||
|
|
||||||
|
// removeCommitHeight[Remote|Local] encodes the height of the
|
||||||
|
// commitment which removed the parent pointer of this
|
||||||
|
// PaymentDescriptor either due to a timeout or a settle. Once both
|
||||||
|
// these heights are below the tail of both chains, the log entries can
|
||||||
|
// safely be removed.
|
||||||
|
removeCommitHeightRemote uint64
|
||||||
|
removeCommitHeightLocal uint64
|
||||||
|
|
||||||
|
// OnionBlob is an opaque blob which is used to complete multi-hop
|
||||||
|
// routing.
|
||||||
|
//
|
||||||
|
// NOTE: Populated only on add payment descriptor entry types.
|
||||||
|
OnionBlob []byte
|
||||||
|
|
||||||
|
// ShaOnionBlob is a sha of the onion blob.
|
||||||
|
//
|
||||||
|
// NOTE: Populated only in payment descriptor with MalformedFail type.
|
||||||
|
ShaOnionBlob [sha256.Size]byte
|
||||||
|
|
||||||
|
// FailReason stores the reason why a particular payment was canceled.
|
||||||
|
//
|
||||||
|
// NOTE: Populate only in fail payment descriptor entry types.
|
||||||
|
FailReason []byte
|
||||||
|
|
||||||
|
// FailCode stores the code why a particular payment was canceled.
|
||||||
|
//
|
||||||
|
// NOTE: Populated only in payment descriptor with MalformedFail type.
|
||||||
|
FailCode lnwire.FailCode
|
||||||
|
|
||||||
|
// [our|their|]PkScript are the raw public key scripts that encodes the
|
||||||
|
// redemption rules for this particular HTLC. These fields will only be
|
||||||
|
// populated iff the EntryType of this PaymentDescriptor is Add.
|
||||||
|
// ourPkScript is the ourPkScript from the context of our local
|
||||||
|
// commitment chain. theirPkScript is the latest pkScript from the
|
||||||
|
// context of the remote commitment chain.
|
||||||
|
//
|
||||||
|
// NOTE: These values may change within the logs themselves, however,
|
||||||
|
// they'll stay consistent within the commitment chain entries
|
||||||
|
// themselves.
|
||||||
|
ourPkScript []byte
|
||||||
|
ourWitnessScript []byte
|
||||||
|
theirPkScript []byte
|
||||||
|
theirWitnessScript []byte
|
||||||
|
|
||||||
|
// EntryType denotes the exact type of the PaymentDescriptor. In the
|
||||||
|
// case of a Timeout, or Settle type, then the Parent field will point
|
||||||
|
// into the log to the HTLC being modified.
|
||||||
|
EntryType updateType
|
||||||
|
|
||||||
|
// isForwarded denotes if an incoming HTLC has been forwarded to any
|
||||||
|
// possible upstream peers in the route.
|
||||||
|
isForwarded bool
|
||||||
|
|
||||||
|
// BlindingPoint is an optional ephemeral key used in route blinding.
|
||||||
|
// This value is set for nodes that are relaying payments inside of a
|
||||||
|
// blinded route (ie, not the introduction node) from update_add_htlc's
|
||||||
|
// TLVs.
|
||||||
|
BlindingPoint lnwire.BlindingPointRecord
|
||||||
|
}
|
197
lnwallet/update_log.go
Normal file
197
lnwallet/update_log.go
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package lnwallet
|
||||||
|
|
||||||
|
import "container/list"
|
||||||
|
|
||||||
|
// updateLog is an append-only log that stores updates to a node's commitment
|
||||||
|
// chain. This structure can be seen as the "mempool" within Lightning where
|
||||||
|
// changes are stored before they're committed to the chain. Once an entry has
|
||||||
|
// been committed in both the local and remote commitment chain, then it can be
|
||||||
|
// removed from this log.
|
||||||
|
//
|
||||||
|
// TODO(roasbeef): create lightning package, move commitment and update to
|
||||||
|
// package?
|
||||||
|
// - also move state machine, separate from lnwallet package
|
||||||
|
// - possible embed updateLog within commitmentChain.
|
||||||
|
type updateLog struct {
|
||||||
|
// logIndex is a monotonically increasing integer that tracks the total
|
||||||
|
// number of update entries ever applied to the log. When sending new
|
||||||
|
// commitment states, we include all updates up to this index.
|
||||||
|
logIndex uint64
|
||||||
|
|
||||||
|
// htlcCounter is a monotonically increasing integer that tracks the
|
||||||
|
// total number of offered HTLC's by the owner of this update log,
|
||||||
|
// hence the `Add` update type. We use a distinct index for this
|
||||||
|
// purpose, as update's that remove entries from the log will be
|
||||||
|
// indexed using this counter.
|
||||||
|
htlcCounter uint64
|
||||||
|
|
||||||
|
// List is the updatelog itself, we embed this value so updateLog has
|
||||||
|
// access to all the method of a list.List.
|
||||||
|
*list.List
|
||||||
|
|
||||||
|
// updateIndex maps a `logIndex` to a particular update entry. It
|
||||||
|
// deals with the four update types:
|
||||||
|
// `Fail|MalformedFail|Settle|FeeUpdate`
|
||||||
|
updateIndex map[uint64]*list.Element
|
||||||
|
|
||||||
|
// htlcIndex maps a `htlcCounter` to an offered HTLC entry, hence the
|
||||||
|
// `Add` update.
|
||||||
|
htlcIndex map[uint64]*list.Element
|
||||||
|
|
||||||
|
// modifiedHtlcs is a set that keeps track of all the current modified
|
||||||
|
// htlcs, hence update types `Fail|MalformedFail|Settle`. A modified
|
||||||
|
// HTLC is one that's present in the log, and has as a pending fail or
|
||||||
|
// settle that's attempting to consume it.
|
||||||
|
modifiedHtlcs map[uint64]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newUpdateLog creates a new updateLog instance.
|
||||||
|
func newUpdateLog(logIndex, htlcCounter uint64) *updateLog {
|
||||||
|
return &updateLog{
|
||||||
|
List: list.New(),
|
||||||
|
updateIndex: make(map[uint64]*list.Element),
|
||||||
|
htlcIndex: make(map[uint64]*list.Element),
|
||||||
|
logIndex: logIndex,
|
||||||
|
htlcCounter: htlcCounter,
|
||||||
|
modifiedHtlcs: make(map[uint64]struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restoreHtlc will "restore" a prior HTLC to the updateLog. We say restore as
|
||||||
|
// this method is intended to be used when re-covering a prior commitment
|
||||||
|
// state. This function differs from appendHtlc in that it won't increment
|
||||||
|
// either of log's counters. If the HTLC is already present, then it is
|
||||||
|
// ignored.
|
||||||
|
func (u *updateLog) restoreHtlc(pd *PaymentDescriptor) {
|
||||||
|
if _, ok := u.htlcIndex[pd.HtlcIndex]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u.htlcIndex[pd.HtlcIndex] = u.PushBack(pd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendUpdate appends a new update to the tip of the updateLog. The entry is
|
||||||
|
// also added to index accordingly.
|
||||||
|
func (u *updateLog) appendUpdate(pd *PaymentDescriptor) {
|
||||||
|
u.updateIndex[u.logIndex] = u.PushBack(pd)
|
||||||
|
u.logIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
// restoreUpdate appends a new update to the tip of the updateLog. The entry is
|
||||||
|
// also added to index accordingly. This function differs from appendUpdate in
|
||||||
|
// that it won't increment the log index counter.
|
||||||
|
func (u *updateLog) restoreUpdate(pd *PaymentDescriptor) {
|
||||||
|
u.updateIndex[pd.LogIndex] = u.PushBack(pd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendHtlc appends a new HTLC offer to the tip of the update log. The entry
|
||||||
|
// is also added to the offer index accordingly.
|
||||||
|
func (u *updateLog) appendHtlc(pd *PaymentDescriptor) {
|
||||||
|
u.htlcIndex[u.htlcCounter] = u.PushBack(pd)
|
||||||
|
u.htlcCounter++
|
||||||
|
|
||||||
|
u.logIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookupHtlc attempts to look up an offered HTLC according to its offer
|
||||||
|
// index. If the entry isn't found, then a nil pointer is returned.
|
||||||
|
func (u *updateLog) lookupHtlc(i uint64) *PaymentDescriptor {
|
||||||
|
htlc, ok := u.htlcIndex[i]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:forcetypeassert
|
||||||
|
return htlc.Value.(*PaymentDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove attempts to remove an entry from the update log. If the entry is
|
||||||
|
// found, then the entry will be removed from the update log and index.
|
||||||
|
func (u *updateLog) removeUpdate(i uint64) {
|
||||||
|
entry := u.updateIndex[i]
|
||||||
|
u.Remove(entry)
|
||||||
|
delete(u.updateIndex, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeHtlc attempts to remove an HTLC offer form the update log. If the
|
||||||
|
// entry is found, then the entry will be removed from both the main log and
|
||||||
|
// the offer index.
|
||||||
|
func (u *updateLog) removeHtlc(i uint64) {
|
||||||
|
entry := u.htlcIndex[i]
|
||||||
|
u.Remove(entry)
|
||||||
|
delete(u.htlcIndex, i)
|
||||||
|
|
||||||
|
delete(u.modifiedHtlcs, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// htlcHasModification returns true if the HTLC identified by the passed index
|
||||||
|
// has a pending modification within the log.
|
||||||
|
func (u *updateLog) htlcHasModification(i uint64) bool {
|
||||||
|
_, o := u.modifiedHtlcs[i]
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// markHtlcModified marks an HTLC as modified based on its HTLC index. After a
|
||||||
|
// call to this method, htlcHasModification will return true until the HTLC is
|
||||||
|
// removed.
|
||||||
|
func (u *updateLog) markHtlcModified(i uint64) {
|
||||||
|
u.modifiedHtlcs[i] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compactLogs performs garbage collection within the log removing HTLCs which
|
||||||
|
// have been removed from the point-of-view of the tail of both chains. The
|
||||||
|
// entries which timeout/settle HTLCs are also removed.
|
||||||
|
func compactLogs(ourLog, theirLog *updateLog,
|
||||||
|
localChainTail, remoteChainTail uint64) {
|
||||||
|
|
||||||
|
compactLog := func(logA, logB *updateLog) {
|
||||||
|
var nextA *list.Element
|
||||||
|
for e := logA.Front(); e != nil; e = nextA {
|
||||||
|
// Assign next iteration element at top of loop because
|
||||||
|
// we may remove the current element from the list,
|
||||||
|
// which can change the iterated sequence.
|
||||||
|
nextA = e.Next()
|
||||||
|
|
||||||
|
//nolint:forcetypeassert
|
||||||
|
htlc := e.Value.(*PaymentDescriptor)
|
||||||
|
|
||||||
|
// We skip Adds, as they will be removed along with the
|
||||||
|
// fail/settles below.
|
||||||
|
if htlc.EntryType == Add {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the HTLC hasn't yet been removed from either
|
||||||
|
// chain, the skip it.
|
||||||
|
if htlc.removeCommitHeightRemote == 0 ||
|
||||||
|
htlc.removeCommitHeightLocal == 0 {
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise if the height of the tail of both chains
|
||||||
|
// is at least the height in which the HTLC was
|
||||||
|
// removed, then evict the settle/timeout entry along
|
||||||
|
// with the original add entry.
|
||||||
|
if remoteChainTail >= htlc.removeCommitHeightRemote &&
|
||||||
|
localChainTail >= htlc.removeCommitHeightLocal {
|
||||||
|
|
||||||
|
// Fee updates have no parent htlcs, so we only
|
||||||
|
// remove the update itself.
|
||||||
|
if htlc.EntryType == FeeUpdate {
|
||||||
|
logA.removeUpdate(htlc.LogIndex)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// The other types (fail/settle) do have a
|
||||||
|
// parent HTLC, so we'll remove that HTLC from
|
||||||
|
// the other log.
|
||||||
|
logA.removeUpdate(htlc.LogIndex)
|
||||||
|
logB.removeHtlc(htlc.ParentIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compactLog(ourLog, theirLog)
|
||||||
|
compactLog(theirLog, ourLog)
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue