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

lightningnetwork / lnd / 14193549836

01 Apr 2025 10:40AM UTC coverage: 69.046% (+0.007%) from 69.039%
14193549836

Pull #9665

github

web-flow
Merge e8825f209 into b01f4e514
Pull Request #9665: kvdb: bump etcd libs to v3.5.12

133439 of 193262 relevant lines covered (69.05%)

22119.45 hits per line

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

62.22
/channeldb/migration_01_to_11/db.go
1
package migration_01_to_11
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "fmt"
7
        "os"
8
        "path/filepath"
9
        "time"
10

11
        "github.com/lightningnetwork/lnd/kvdb"
12
)
13

14
const (
15
        dbName           = "channel.db"
16
        dbFilePermission = 0600
17
)
18

19
// migration is a function which takes a prior outdated version of the database
20
// instances and mutates the key/bucket structure to arrive at a more
21
// up-to-date version of the database.
22
type migration func(tx kvdb.RwTx) error
23

24
var (
25
        // Big endian is the preferred byte order, due to cursor scans over
26
        // integer keys iterating in order.
27
        byteOrder = binary.BigEndian
28
)
29

30
// DB is the primary datastore for the lnd daemon. The database stores
31
// information related to nodes, routing data, open/closed channels, fee
32
// schedules, and reputation data.
33
type DB struct {
34
        kvdb.Backend
35
        dbPath string
36
        graph  *ChannelGraph
37
        now    func() time.Time
38
}
39

40
// Open opens an existing channeldb. Any necessary schemas migrations due to
41
// updates will take place as necessary.
42
func Open(dbPath string, modifiers ...OptionModifier) (*DB, error) {
9✔
43
        path := filepath.Join(dbPath, dbName)
9✔
44

9✔
45
        if !fileExists(path) {
18✔
46
                if err := createChannelDB(dbPath); err != nil {
9✔
47
                        return nil, err
×
48
                }
×
49
        }
50

51
        opts := DefaultOptions()
9✔
52
        for _, modifier := range modifiers {
9✔
53
                modifier(&opts)
×
54
        }
×
55

56
        // Specify bbolt freelist options to reduce heap pressure in case the
57
        // freelist grows to be very large.
58
        bdb, err := kvdb.Open(
9✔
59
                kvdb.BoltBackendName, path,
9✔
60
                opts.NoFreelistSync, opts.DBTimeout,
9✔
61
        )
9✔
62
        if err != nil {
9✔
63
                return nil, err
×
64
        }
×
65

66
        chanDB := &DB{
9✔
67
                Backend: bdb,
9✔
68
                dbPath:  dbPath,
9✔
69
                now:     time.Now,
9✔
70
        }
9✔
71
        chanDB.graph = newChannelGraph(
9✔
72
                chanDB, opts.RejectCacheSize, opts.ChannelCacheSize,
9✔
73
        )
9✔
74

9✔
75
        return chanDB, nil
9✔
76
}
77

78
// createChannelDB creates and initializes a fresh version of channeldb. In
79
// the case that the target path has not yet been created or doesn't yet exist,
80
// then the path is created. Additionally, all required top-level buckets used
81
// within the database are created.
82
func createChannelDB(dbPath string) error {
9✔
83
        if !fileExists(dbPath) {
9✔
84
                if err := os.MkdirAll(dbPath, 0700); err != nil {
×
85
                        return err
×
86
                }
×
87
        }
88

89
        path := filepath.Join(dbPath, dbName)
9✔
90
        bdb, err := kvdb.Create(
9✔
91
                kvdb.BoltBackendName, path, false, kvdb.DefaultDBTimeout,
9✔
92
        )
9✔
93
        if err != nil {
9✔
94
                return err
×
95
        }
×
96

97
        err = kvdb.Update(bdb, func(tx kvdb.RwTx) error {
18✔
98
                if _, err := tx.CreateTopLevelBucket(openChannelBucket); err != nil {
9✔
99
                        return err
×
100
                }
×
101
                if _, err := tx.CreateTopLevelBucket(closedChannelBucket); err != nil {
9✔
102
                        return err
×
103
                }
×
104

105
                if _, err := tx.CreateTopLevelBucket(invoiceBucket); err != nil {
9✔
106
                        return err
×
107
                }
×
108

109
                if _, err := tx.CreateTopLevelBucket(paymentBucket); err != nil {
9✔
110
                        return err
×
111
                }
×
112

113
                nodes, err := tx.CreateTopLevelBucket(nodeBucket)
9✔
114
                if err != nil {
9✔
115
                        return err
×
116
                }
×
117
                _, err = nodes.CreateBucket(aliasIndexBucket)
9✔
118
                if err != nil {
9✔
119
                        return err
×
120
                }
×
121
                _, err = nodes.CreateBucket(nodeUpdateIndexBucket)
9✔
122
                if err != nil {
9✔
123
                        return err
×
124
                }
×
125

126
                edges, err := tx.CreateTopLevelBucket(edgeBucket)
9✔
127
                if err != nil {
9✔
128
                        return err
×
129
                }
×
130
                if _, err := edges.CreateBucket(edgeIndexBucket); err != nil {
9✔
131
                        return err
×
132
                }
×
133
                if _, err := edges.CreateBucket(edgeUpdateIndexBucket); err != nil {
9✔
134
                        return err
×
135
                }
×
136
                if _, err := edges.CreateBucket(channelPointBucket); err != nil {
9✔
137
                        return err
×
138
                }
×
139
                if _, err := edges.CreateBucket(zombieBucket); err != nil {
9✔
140
                        return err
×
141
                }
×
142

143
                graphMeta, err := tx.CreateTopLevelBucket(graphMetaBucket)
9✔
144
                if err != nil {
9✔
145
                        return err
×
146
                }
×
147
                _, err = graphMeta.CreateBucket(pruneLogBucket)
9✔
148
                if err != nil {
9✔
149
                        return err
×
150
                }
×
151

152
                if _, err := tx.CreateTopLevelBucket(metaBucket); err != nil {
9✔
153
                        return err
×
154
                }
×
155

156
                meta := &Meta{
9✔
157
                        DbVersionNumber: 0,
9✔
158
                }
9✔
159
                return putMeta(meta, tx)
9✔
160
        }, func() {})
9✔
161
        if err != nil {
9✔
162
                return fmt.Errorf("unable to create new channeldb")
×
163
        }
×
164

165
        return bdb.Close()
9✔
166
}
167

168
// fileExists returns true if the file exists, and false otherwise.
169
func fileExists(path string) bool {
18✔
170
        if _, err := os.Stat(path); err != nil {
27✔
171
                if os.IsNotExist(err) {
18✔
172
                        return false
9✔
173
                }
9✔
174
        }
175

176
        return true
9✔
177
}
178

179
// FetchClosedChannels attempts to fetch all closed channels from the database.
180
// The pendingOnly bool toggles if channels that aren't yet fully closed should
181
// be returned in the response or not. When a channel was cooperatively closed,
182
// it becomes fully closed after a single confirmation.  When a channel was
183
// forcibly closed, it will become fully closed after _all_ the pending funds
184
// (if any) have been swept.
185
func (d *DB) FetchClosedChannels(pendingOnly bool) ([]*ChannelCloseSummary, error) {
3✔
186
        var chanSummaries []*ChannelCloseSummary
3✔
187

3✔
188
        if err := kvdb.View(d, func(tx kvdb.RTx) error {
6✔
189
                closeBucket := tx.ReadBucket(closedChannelBucket)
3✔
190
                if closeBucket == nil {
3✔
191
                        return ErrNoClosedChannels
×
192
                }
×
193

194
                return closeBucket.ForEach(func(chanID []byte, summaryBytes []byte) error {
6✔
195
                        summaryReader := bytes.NewReader(summaryBytes)
3✔
196
                        chanSummary, err := deserializeCloseChannelSummary(summaryReader)
3✔
197
                        if err != nil {
3✔
198
                                return err
×
199
                        }
×
200

201
                        // If the query specified to only include pending
202
                        // channels, then we'll skip any channels which aren't
203
                        // currently pending.
204
                        if !chanSummary.IsPending && pendingOnly {
3✔
205
                                return nil
×
206
                        }
×
207

208
                        chanSummaries = append(chanSummaries, chanSummary)
3✔
209
                        return nil
3✔
210
                })
211
        }, func() {
3✔
212
                chanSummaries = nil
3✔
213
        }); err != nil {
3✔
214
                return nil, err
×
215
        }
×
216

217
        return chanSummaries, nil
3✔
218
}
219

220
// ChannelGraph returns a new instance of the directed channel graph.
221
func (d *DB) ChannelGraph() *ChannelGraph {
10✔
222
        return d.graph
10✔
223
}
10✔
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