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

lightningnetwork / lnd / 12026968820

26 Nov 2024 08:48AM UTC coverage: 49.896% (-9.1%) from 58.999%
12026968820

Pull #9303

github

yyforyongyu
lnwallet: add debug logs
Pull Request #9303: htlcswitch+routing: handle nil pointer dereference properly

20 of 23 new or added lines in 4 files covered. (86.96%)

25375 existing lines in 428 files now uncovered.

99993 of 200404 relevant lines covered (49.9%)

2.07 hits per line

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

62.98
/channeldb/nodes.go
1
package channeldb
2

3
import (
4
        "bytes"
5
        "io"
6
        "net"
7
        "time"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/btcsuite/btcd/wire"
11
        "github.com/lightningnetwork/lnd/kvdb"
12
)
13

14
var (
15
        // nodeInfoBucket stores metadata pertaining to nodes that we've had
16
        // direct channel-based correspondence with. This bucket allows one to
17
        // query for all open channels pertaining to the node by exploring each
18
        // node's sub-bucket within the openChanBucket.
19
        nodeInfoBucket = []byte("nib")
20
)
21

22
// LinkNode stores metadata related to node's that we have/had a direct
23
// channel open with. Information such as the Bitcoin network the node
24
// advertised, and its identity public key are also stored. Additionally, this
25
// struct and the bucket its stored within have store data similar to that of
26
// Bitcoin's addrmanager. The TCP address information stored within the struct
27
// can be used to establish persistent connections will all channel
28
// counterparties on daemon startup.
29
//
30
// TODO(roasbeef): also add current OnionKey plus rotation schedule?
31
// TODO(roasbeef): add bitfield for supported services
32
//   - possibly add a wire.NetAddress type, type
33
type LinkNode struct {
34
        // Network indicates the Bitcoin network that the LinkNode advertises
35
        // for incoming channel creation.
36
        Network wire.BitcoinNet
37

38
        // IdentityPub is the node's current identity public key. Any
39
        // channel/topology related information received by this node MUST be
40
        // signed by this public key.
41
        IdentityPub *btcec.PublicKey
42

43
        // LastSeen tracks the last time this node was seen within the network.
44
        // A node should be marked as seen if the daemon either is able to
45
        // establish an outgoing connection to the node or receives a new
46
        // incoming connection from the node. This timestamp (stored in unix
47
        // epoch) may be used within a heuristic which aims to determine when a
48
        // channel should be unilaterally closed due to inactivity.
49
        //
50
        // TODO(roasbeef): replace with block hash/height?
51
        //  * possibly add a time-value metric into the heuristic?
52
        LastSeen time.Time
53

54
        // Addresses is a list of IP address in which either we were able to
55
        // reach the node over in the past, OR we received an incoming
56
        // authenticated connection for the stored identity public key.
57
        Addresses []net.Addr
58

59
        // db is the database instance this node was fetched from. This is used
60
        // to sync back the node's state if it is updated.
61
        db *LinkNodeDB
62
}
63

64
// NewLinkNode creates a new LinkNode from the provided parameters, which is
65
// backed by an instance of a link node DB.
66
func NewLinkNode(db *LinkNodeDB, bitNet wire.BitcoinNet, pub *btcec.PublicKey,
67
        addrs ...net.Addr) *LinkNode {
4✔
68

4✔
69
        return &LinkNode{
4✔
70
                Network:     bitNet,
4✔
71
                IdentityPub: pub,
4✔
72
                LastSeen:    time.Now(),
4✔
73
                Addresses:   addrs,
4✔
74
                db:          db,
4✔
75
        }
4✔
76
}
4✔
77

78
// UpdateLastSeen updates the last time this node was directly encountered on
79
// the Lightning Network.
UNCOV
80
func (l *LinkNode) UpdateLastSeen(lastSeen time.Time) error {
×
UNCOV
81
        l.LastSeen = lastSeen
×
UNCOV
82

×
UNCOV
83
        return l.Sync()
×
UNCOV
84
}
×
85

86
// AddAddress appends the specified TCP address to the list of known addresses
87
// this node is/was known to be reachable at.
UNCOV
88
func (l *LinkNode) AddAddress(addr net.Addr) error {
×
UNCOV
89
        for _, a := range l.Addresses {
×
UNCOV
90
                if a.String() == addr.String() {
×
91
                        return nil
×
92
                }
×
93
        }
94

UNCOV
95
        l.Addresses = append(l.Addresses, addr)
×
UNCOV
96

×
UNCOV
97
        return l.Sync()
×
98
}
99

100
// Sync performs a full database sync which writes the current up-to-date data
101
// within the struct to the database.
UNCOV
102
func (l *LinkNode) Sync() error {
×
UNCOV
103
        // Finally update the database by storing the link node and updating
×
UNCOV
104
        // any relevant indexes.
×
UNCOV
105
        return kvdb.Update(l.db.backend, func(tx kvdb.RwTx) error {
×
UNCOV
106
                nodeMetaBucket := tx.ReadWriteBucket(nodeInfoBucket)
×
UNCOV
107
                if nodeMetaBucket == nil {
×
108
                        return ErrLinkNodesNotFound
×
109
                }
×
110

UNCOV
111
                return putLinkNode(nodeMetaBucket, l)
×
UNCOV
112
        }, func() {})
×
113
}
114

115
// putLinkNode serializes then writes the encoded version of the passed link
116
// node into the nodeMetaBucket. This function is provided in order to allow
117
// the ability to re-use a database transaction across many operations.
118
func putLinkNode(nodeMetaBucket kvdb.RwBucket, l *LinkNode) error {
4✔
119
        // First serialize the LinkNode into its raw-bytes encoding.
4✔
120
        var b bytes.Buffer
4✔
121
        if err := serializeLinkNode(&b, l); err != nil {
4✔
122
                return err
×
123
        }
×
124

125
        // Finally insert the link-node into the node metadata bucket keyed
126
        // according to the its pubkey serialized in compressed form.
127
        nodePub := l.IdentityPub.SerializeCompressed()
4✔
128
        return nodeMetaBucket.Put(nodePub, b.Bytes())
4✔
129
}
130

131
// LinkNodeDB is a database that keeps track of all link nodes.
132
type LinkNodeDB struct {
133
        backend kvdb.Backend
134
}
135

136
// DeleteLinkNode removes the link node with the given identity from the
137
// database.
138
func (l *LinkNodeDB) DeleteLinkNode(identity *btcec.PublicKey) error {
4✔
139
        return kvdb.Update(l.backend, func(tx kvdb.RwTx) error {
8✔
140
                return deleteLinkNode(tx, identity)
4✔
141
        }, func() {})
8✔
142
}
143

144
func deleteLinkNode(tx kvdb.RwTx, identity *btcec.PublicKey) error {
4✔
145
        nodeMetaBucket := tx.ReadWriteBucket(nodeInfoBucket)
4✔
146
        if nodeMetaBucket == nil {
4✔
147
                return ErrLinkNodesNotFound
×
148
        }
×
149

150
        pubKey := identity.SerializeCompressed()
4✔
151
        return nodeMetaBucket.Delete(pubKey)
4✔
152
}
153

154
// FetchLinkNode attempts to lookup the data for a LinkNode based on a target
155
// identity public key. If a particular LinkNode for the passed identity public
156
// key cannot be found, then ErrNodeNotFound if returned.
157
func (l *LinkNodeDB) FetchLinkNode(identity *btcec.PublicKey) (*LinkNode, error) {
4✔
158
        var linkNode *LinkNode
4✔
159
        err := kvdb.View(l.backend, func(tx kvdb.RTx) error {
8✔
160
                node, err := fetchLinkNode(tx, identity)
4✔
161
                if err != nil {
4✔
UNCOV
162
                        return err
×
UNCOV
163
                }
×
164

165
                linkNode = node
4✔
166
                return nil
4✔
167
        }, func() {
4✔
168
                linkNode = nil
4✔
169
        })
4✔
170

171
        return linkNode, err
4✔
172
}
173

174
func fetchLinkNode(tx kvdb.RTx, targetPub *btcec.PublicKey) (*LinkNode, error) {
4✔
175
        // First fetch the bucket for storing node metadata, bailing out early
4✔
176
        // if it hasn't been created yet.
4✔
177
        nodeMetaBucket := tx.ReadBucket(nodeInfoBucket)
4✔
178
        if nodeMetaBucket == nil {
4✔
179
                return nil, ErrLinkNodesNotFound
×
180
        }
×
181

182
        // If a link node for that particular public key cannot be located,
183
        // then exit early with an ErrNodeNotFound.
184
        pubKey := targetPub.SerializeCompressed()
4✔
185
        nodeBytes := nodeMetaBucket.Get(pubKey)
4✔
186
        if nodeBytes == nil {
4✔
UNCOV
187
                return nil, ErrNodeNotFound
×
UNCOV
188
        }
×
189

190
        // Finally, decode and allocate a fresh LinkNode object to be returned
191
        // to the caller.
192
        nodeReader := bytes.NewReader(nodeBytes)
4✔
193
        return deserializeLinkNode(nodeReader)
4✔
194
}
195

196
// TODO(roasbeef): update link node addrs in server upon connection
197

198
// FetchAllLinkNodes starts a new database transaction to fetch all nodes with
199
// whom we have active channels with.
200
func (l *LinkNodeDB) FetchAllLinkNodes() ([]*LinkNode, error) {
4✔
201
        var linkNodes []*LinkNode
4✔
202
        err := kvdb.View(l.backend, func(tx kvdb.RTx) error {
8✔
203
                nodes, err := fetchAllLinkNodes(tx)
4✔
204
                if err != nil {
4✔
205
                        return err
×
206
                }
×
207

208
                linkNodes = nodes
4✔
209
                return nil
4✔
210
        }, func() {
4✔
211
                linkNodes = nil
4✔
212
        })
4✔
213
        if err != nil {
4✔
214
                return nil, err
×
215
        }
×
216

217
        return linkNodes, nil
4✔
218
}
219

220
// fetchAllLinkNodes uses an existing database transaction to fetch all nodes
221
// with whom we have active channels with.
222
func fetchAllLinkNodes(tx kvdb.RTx) ([]*LinkNode, error) {
4✔
223
        nodeMetaBucket := tx.ReadBucket(nodeInfoBucket)
4✔
224
        if nodeMetaBucket == nil {
4✔
225
                return nil, ErrLinkNodesNotFound
×
226
        }
×
227

228
        var linkNodes []*LinkNode
4✔
229
        err := nodeMetaBucket.ForEach(func(k, v []byte) error {
8✔
230
                if v == nil {
4✔
231
                        return nil
×
232
                }
×
233

234
                nodeReader := bytes.NewReader(v)
4✔
235
                linkNode, err := deserializeLinkNode(nodeReader)
4✔
236
                if err != nil {
4✔
237
                        return err
×
238
                }
×
239

240
                linkNodes = append(linkNodes, linkNode)
4✔
241
                return nil
4✔
242
        })
243
        if err != nil {
4✔
244
                return nil, err
×
245
        }
×
246

247
        return linkNodes, nil
4✔
248
}
249

250
func serializeLinkNode(w io.Writer, l *LinkNode) error {
4✔
251
        var buf [8]byte
4✔
252

4✔
253
        byteOrder.PutUint32(buf[:4], uint32(l.Network))
4✔
254
        if _, err := w.Write(buf[:4]); err != nil {
4✔
255
                return err
×
256
        }
×
257

258
        serializedID := l.IdentityPub.SerializeCompressed()
4✔
259
        if _, err := w.Write(serializedID); err != nil {
4✔
260
                return err
×
261
        }
×
262

263
        seenUnix := uint64(l.LastSeen.Unix())
4✔
264
        byteOrder.PutUint64(buf[:], seenUnix)
4✔
265
        if _, err := w.Write(buf[:]); err != nil {
4✔
266
                return err
×
267
        }
×
268

269
        numAddrs := uint32(len(l.Addresses))
4✔
270
        byteOrder.PutUint32(buf[:4], numAddrs)
4✔
271
        if _, err := w.Write(buf[:4]); err != nil {
4✔
272
                return err
×
273
        }
×
274

275
        for _, addr := range l.Addresses {
8✔
276
                if err := serializeAddr(w, addr); err != nil {
4✔
277
                        return err
×
278
                }
×
279
        }
280

281
        return nil
4✔
282
}
283

284
func deserializeLinkNode(r io.Reader) (*LinkNode, error) {
4✔
285
        var (
4✔
286
                err error
4✔
287
                buf [8]byte
4✔
288
        )
4✔
289

4✔
290
        node := &LinkNode{}
4✔
291

4✔
292
        if _, err := io.ReadFull(r, buf[:4]); err != nil {
4✔
293
                return nil, err
×
294
        }
×
295
        node.Network = wire.BitcoinNet(byteOrder.Uint32(buf[:4]))
4✔
296

4✔
297
        var pub [33]byte
4✔
298
        if _, err := io.ReadFull(r, pub[:]); err != nil {
4✔
299
                return nil, err
×
300
        }
×
301
        node.IdentityPub, err = btcec.ParsePubKey(pub[:])
4✔
302
        if err != nil {
4✔
303
                return nil, err
×
304
        }
×
305

306
        if _, err := io.ReadFull(r, buf[:]); err != nil {
4✔
307
                return nil, err
×
308
        }
×
309
        node.LastSeen = time.Unix(int64(byteOrder.Uint64(buf[:])), 0)
4✔
310

4✔
311
        if _, err := io.ReadFull(r, buf[:4]); err != nil {
4✔
312
                return nil, err
×
313
        }
×
314
        numAddrs := byteOrder.Uint32(buf[:4])
4✔
315

4✔
316
        node.Addresses = make([]net.Addr, numAddrs)
4✔
317
        for i := uint32(0); i < numAddrs; i++ {
8✔
318
                addr, err := deserializeAddr(r)
4✔
319
                if err != nil {
4✔
320
                        return nil, err
×
321
                }
×
322
                node.Addresses[i] = addr
4✔
323
        }
324

325
        return node, nil
4✔
326
}
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