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

lightningnetwork / lnd / 12033440129

26 Nov 2024 03:03PM UTC coverage: 48.738% (-10.3%) from 58.999%
12033440129

Pull #9309

github

yyforyongyu
gomod: update `btcd` for shutdown fix
Pull Request #9309: chainntnfs: fix `TestHistoricalConfDetailsTxIndex`

97664 of 200385 relevant lines covered (48.74%)

0.52 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 {
1✔
68

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

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

×
83
        return l.Sync()
×
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.
88
func (l *LinkNode) AddAddress(addr net.Addr) error {
×
89
        for _, a := range l.Addresses {
×
90
                if a.String() == addr.String() {
×
91
                        return nil
×
92
                }
×
93
        }
94

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

×
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.
102
func (l *LinkNode) Sync() error {
×
103
        // Finally update the database by storing the link node and updating
×
104
        // any relevant indexes.
×
105
        return kvdb.Update(l.db.backend, func(tx kvdb.RwTx) error {
×
106
                nodeMetaBucket := tx.ReadWriteBucket(nodeInfoBucket)
×
107
                if nodeMetaBucket == nil {
×
108
                        return ErrLinkNodesNotFound
×
109
                }
×
110

111
                return putLinkNode(nodeMetaBucket, l)
×
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 {
1✔
119
        // First serialize the LinkNode into its raw-bytes encoding.
1✔
120
        var b bytes.Buffer
1✔
121
        if err := serializeLinkNode(&b, l); err != nil {
1✔
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()
1✔
128
        return nodeMetaBucket.Put(nodePub, b.Bytes())
1✔
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 {
1✔
139
        return kvdb.Update(l.backend, func(tx kvdb.RwTx) error {
2✔
140
                return deleteLinkNode(tx, identity)
1✔
141
        }, func() {})
2✔
142
}
143

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

150
        pubKey := identity.SerializeCompressed()
1✔
151
        return nodeMetaBucket.Delete(pubKey)
1✔
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) {
1✔
158
        var linkNode *LinkNode
1✔
159
        err := kvdb.View(l.backend, func(tx kvdb.RTx) error {
2✔
160
                node, err := fetchLinkNode(tx, identity)
1✔
161
                if err != nil {
1✔
162
                        return err
×
163
                }
×
164

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

171
        return linkNode, err
1✔
172
}
173

174
func fetchLinkNode(tx kvdb.RTx, targetPub *btcec.PublicKey) (*LinkNode, error) {
1✔
175
        // First fetch the bucket for storing node metadata, bailing out early
1✔
176
        // if it hasn't been created yet.
1✔
177
        nodeMetaBucket := tx.ReadBucket(nodeInfoBucket)
1✔
178
        if nodeMetaBucket == nil {
1✔
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()
1✔
185
        nodeBytes := nodeMetaBucket.Get(pubKey)
1✔
186
        if nodeBytes == nil {
1✔
187
                return nil, ErrNodeNotFound
×
188
        }
×
189

190
        // Finally, decode and allocate a fresh LinkNode object to be returned
191
        // to the caller.
192
        nodeReader := bytes.NewReader(nodeBytes)
1✔
193
        return deserializeLinkNode(nodeReader)
1✔
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) {
1✔
201
        var linkNodes []*LinkNode
1✔
202
        err := kvdb.View(l.backend, func(tx kvdb.RTx) error {
2✔
203
                nodes, err := fetchAllLinkNodes(tx)
1✔
204
                if err != nil {
1✔
205
                        return err
×
206
                }
×
207

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

217
        return linkNodes, nil
1✔
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) {
1✔
223
        nodeMetaBucket := tx.ReadBucket(nodeInfoBucket)
1✔
224
        if nodeMetaBucket == nil {
1✔
225
                return nil, ErrLinkNodesNotFound
×
226
        }
×
227

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

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

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

247
        return linkNodes, nil
1✔
248
}
249

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

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

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

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

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

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

281
        return nil
1✔
282
}
283

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

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

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

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

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

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

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

325
        return node, nil
1✔
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