• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.16
/lnwallet/update_log.go
1
package lnwallet
2

3
import (
4
        "github.com/lightningnetwork/lnd/fn/v2"
5
)
6

7
// updateLog is an append-only log that stores updates to a node's commitment
8
// chain. This structure can be seen as the "mempool" within Lightning where
9
// changes are stored before they're committed to the chain. Once an entry has
10
// been committed in both the local and remote commitment chain, then it can be
11
// removed from this log.
12
//
13
// TODO(roasbeef): create lightning package, move commitment and update to
14
// package?
15
//   - also move state machine, separate from lnwallet package
16
//   - possible embed updateLog within commitmentChain.
17
type updateLog struct {
18
        // logIndex is a monotonically increasing integer that tracks the total
19
        // number of update entries ever applied to the log. When sending new
20
        // commitment states, we include all updates up to this index.
21
        logIndex uint64
22

23
        // htlcCounter is a monotonically increasing integer that tracks the
24
        // total number of offered HTLC's by the owner of this update log,
25
        // hence the `Add` update type. We use a distinct index for this
26
        // purpose, as update's that remove entries from the log will be
27
        // indexed using this counter.
28
        htlcCounter uint64
29

30
        // List is the updatelog itself, we embed this value so updateLog has
31
        // access to all the method of a list.List.
32
        *fn.List[*paymentDescriptor]
33

34
        // updateIndex maps a `logIndex` to a particular update entry. It
35
        // deals with the four update types:
36
        //   `Fail|MalformedFail|Settle|FeeUpdate`
37
        updateIndex map[uint64]*fn.Node[*paymentDescriptor]
38

39
        // htlcIndex maps a `htlcCounter` to an offered HTLC entry, hence the
40
        // `Add` update.
41
        htlcIndex map[uint64]*fn.Node[*paymentDescriptor]
42

43
        // modifiedHtlcs is a set that keeps track of all the current modified
44
        // htlcs, hence update types `Fail|MalformedFail|Settle`. A modified
45
        // HTLC is one that's present in the log, and has as a pending fail or
46
        // settle that's attempting to consume it.
47
        modifiedHtlcs fn.Set[uint64]
48
}
49

50
// newUpdateLog creates a new updateLog instance.
51
func newUpdateLog(logIndex, htlcCounter uint64) *updateLog {
3✔
52
        return &updateLog{
3✔
53
                List:          fn.NewList[*paymentDescriptor](),
3✔
54
                updateIndex:   make(map[uint64]*fn.Node[*paymentDescriptor]),
3✔
55
                htlcIndex:     make(map[uint64]*fn.Node[*paymentDescriptor]),
3✔
56
                logIndex:      logIndex,
3✔
57
                htlcCounter:   htlcCounter,
3✔
58
                modifiedHtlcs: fn.NewSet[uint64](),
3✔
59
        }
3✔
60
}
3✔
61

62
// restoreHtlc will "restore" a prior HTLC to the updateLog. We say restore as
63
// this method is intended to be used when re-covering a prior commitment
64
// state. This function differs from appendHtlc in that it won't increment
65
// either of log's counters. If the HTLC is already present, then it is
66
// ignored.
67
func (u *updateLog) restoreHtlc(pd *paymentDescriptor) {
3✔
68
        if _, ok := u.htlcIndex[pd.HtlcIndex]; ok {
3✔
69
                return
×
70
        }
×
71

72
        u.htlcIndex[pd.HtlcIndex] = u.PushBack(pd)
3✔
73
}
74

75
// appendUpdate appends a new update to the tip of the updateLog. The entry is
76
// also added to index accordingly.
77
func (u *updateLog) appendUpdate(pd *paymentDescriptor) {
3✔
78
        u.updateIndex[u.logIndex] = u.PushBack(pd)
3✔
79
        u.logIndex++
3✔
80
}
3✔
81

82
// restoreUpdate appends a new update to the tip of the updateLog. The entry is
83
// also added to index accordingly. This function differs from appendUpdate in
84
// that it won't increment the log index counter.
UNCOV
85
func (u *updateLog) restoreUpdate(pd *paymentDescriptor) {
×
UNCOV
86
        u.updateIndex[pd.LogIndex] = u.PushBack(pd)
×
UNCOV
87
}
×
88

89
// appendHtlc appends a new HTLC offer to the tip of the update log. The entry
90
// is also added to the offer index accordingly.
91
func (u *updateLog) appendHtlc(pd *paymentDescriptor) {
3✔
92
        u.htlcIndex[u.htlcCounter] = u.PushBack(pd)
3✔
93
        u.htlcCounter++
3✔
94

3✔
95
        u.logIndex++
3✔
96
}
3✔
97

98
// lookupHtlc attempts to look up an offered HTLC according to its offer
99
// index. If the entry isn't found, then a nil pointer is returned.
100
func (u *updateLog) lookupHtlc(i uint64) *paymentDescriptor {
3✔
101
        htlc, ok := u.htlcIndex[i]
3✔
102
        if !ok {
3✔
UNCOV
103
                return nil
×
UNCOV
104
        }
×
105

106
        return htlc.Value
3✔
107
}
108

109
// remove attempts to remove an entry from the update log. If the entry is
110
// found, then the entry will be removed from the update log and index.
111
func (u *updateLog) removeUpdate(i uint64) {
3✔
112
        entry := u.updateIndex[i]
3✔
113
        u.Remove(entry)
3✔
114
        delete(u.updateIndex, i)
3✔
115
}
3✔
116

117
// removeHtlc attempts to remove an HTLC offer form the update log. If the
118
// entry is found, then the entry will be removed from both the main log and
119
// the offer index.
120
func (u *updateLog) removeHtlc(i uint64) {
3✔
121
        entry := u.htlcIndex[i]
3✔
122
        u.Remove(entry)
3✔
123
        delete(u.htlcIndex, i)
3✔
124

3✔
125
        u.modifiedHtlcs.Remove(i)
3✔
126
}
3✔
127

128
// htlcHasModification returns true if the HTLC identified by the passed index
129
// has a pending modification within the log.
130
func (u *updateLog) htlcHasModification(i uint64) bool {
3✔
131
        return u.modifiedHtlcs.Contains(i)
3✔
132
}
3✔
133

134
// markHtlcModified marks an HTLC as modified based on its HTLC index. After a
135
// call to this method, htlcHasModification will return true until the HTLC is
136
// removed.
137
func (u *updateLog) markHtlcModified(i uint64) {
3✔
138
        u.modifiedHtlcs.Add(i)
3✔
139
}
3✔
140

141
// compactLogs performs garbage collection within the log removing HTLCs which
142
// have been removed from the point-of-view of the tail of both chains. The
143
// entries which timeout/settle HTLCs are also removed.
144
func compactLogs(ourLog, theirLog *updateLog,
145
        localChainTail, remoteChainTail uint64) {
3✔
146

3✔
147
        compactLog := func(logA, logB *updateLog) {
6✔
148
                var nextA *fn.Node[*paymentDescriptor]
3✔
149
                for e := logA.Front(); e != nil; e = nextA {
6✔
150
                        // Assign next iteration element at top of loop because
3✔
151
                        // we may remove the current element from the list,
3✔
152
                        // which can change the iterated sequence.
3✔
153
                        nextA = e.Next()
3✔
154

3✔
155
                        htlc := e.Value
3✔
156
                        rmvHeights := htlc.removeCommitHeights
3✔
157

3✔
158
                        // We skip Adds, as they will be removed along with the
3✔
159
                        // fail/settles below.
3✔
160
                        if htlc.EntryType == Add {
6✔
161
                                continue
3✔
162
                        }
163

164
                        // If the HTLC hasn't yet been removed from either
165
                        // chain, the skip it.
166
                        if rmvHeights.Remote == 0 || rmvHeights.Local == 0 {
6✔
167
                                continue
3✔
168
                        }
169

170
                        // Otherwise if the height of the tail of both chains
171
                        // is at least the height in which the HTLC was
172
                        // removed, then evict the settle/timeout entry along
173
                        // with the original add entry.
174
                        if remoteChainTail >= rmvHeights.Remote &&
3✔
175
                                localChainTail >= rmvHeights.Local {
6✔
176

3✔
177
                                // Fee updates have no parent htlcs, so we only
3✔
178
                                // remove the update itself.
3✔
179
                                if htlc.EntryType == FeeUpdate {
3✔
UNCOV
180
                                        logA.removeUpdate(htlc.LogIndex)
×
UNCOV
181
                                        continue
×
182
                                }
183

184
                                // The other types (fail/settle) do have a
185
                                // parent HTLC, so we'll remove that HTLC from
186
                                // the other log.
187
                                logA.removeUpdate(htlc.LogIndex)
3✔
188
                                logB.removeHtlc(htlc.ParentIndex)
3✔
189
                        }
190
                }
191
        }
192

193
        compactLog(ourLog, theirLog)
3✔
194
        compactLog(theirLog, ourLog)
3✔
195
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc