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

lightningnetwork / lnd / 19693971034

26 Nov 2025 05:51AM UTC coverage: 65.181%. First build
19693971034

Pull #10339

github

web-flow
Merge 59ddd4354 into c746aeed3
Pull Request #10339: [g175:2] graph/db: v2 columns and v2 node CRUD

205 of 390 new or added lines in 11 files covered. (52.56%)

137687 of 211237 relevant lines covered (65.18%)

20739.78 hits per line

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

78.64
/graph/db/models/node.go
1
package models
2

3
import (
4
        "fmt"
5
        "image/color"
6
        "net"
7
        "time"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/lightningnetwork/lnd/fn/v2"
11
        "github.com/lightningnetwork/lnd/lnwire"
12
        "github.com/lightningnetwork/lnd/routing/route"
13
)
14

15
// Node represents an individual vertex/node within the channel graph.
16
// A node is connected to other nodes by one or more channel edges emanating
17
// from it. As the graph is directed, a node will also have an incoming edge
18
// attached to it for each outgoing edge.
19
type Node struct {
20
        // Version is the gossip version that this node was advertised on.
21
        Version lnwire.GossipVersion
22

23
        // PubKeyBytes is the raw bytes of the public key of the target node.
24
        PubKeyBytes [33]byte
25
        pubKey      *btcec.PublicKey
26

27
        // LastUpdate is the last time the vertex information for this node has
28
        // been updated.
29
        LastUpdate time.Time
30

31
        // LastBlockHeight is the block height that timestamps the last update
32
        // we received for this node. This is only used if this is a V2 node
33
        // announcement.
34
        LastBlockHeight uint32
35

36
        // Address is the TCP address this node is reachable over.
37
        Addresses []net.Addr
38

39
        // Color is the selected color for the node.
40
        Color fn.Option[color.RGBA]
41

42
        // Alias is a nick-name for the node. The alias can be used to confirm
43
        // a node's identity or to serve as a short ID for an address book.
44
        Alias fn.Option[string]
45

46
        // AuthSigBytes is the raw signature under the advertised public key
47
        // which serves to authenticate the attributes announced by this node.
48
        AuthSigBytes []byte
49

50
        // Features is the list of protocol features supported by this node.
51
        Features *lnwire.FeatureVector
52

53
        // ExtraOpaqueData is the set of data that was appended to this
54
        // message, some of which we may not actually know how to iterate or
55
        // parse. By holding onto this data, we ensure that we're able to
56
        // properly validate the set of signatures that cover these new fields,
57
        // and ensure we're able to make upgrades to the network in a forwards
58
        // compatible manner. This is only used for V1 node announcements.
59
        ExtraOpaqueData []byte
60

61
        // ExtraSignedFields is a map of extra fields that are covered by the
62
        // node announcement's signature that we have not explicitly parsed.
63
        // This is only used for version 2 node announcements and beyond.
64
        ExtraSignedFields map[uint64][]byte
65
}
66

67
// NodeV1Fields houses the fields that are specific to a version 1 node
68
// announcement.
69
type NodeV1Fields struct {
70
        // Address is the TCP address this node is reachable over.
71
        Addresses []net.Addr
72

73
        // AuthSigBytes is the raw signature under the advertised public key
74
        // which serves to authenticate the attributes announced by this node.
75
        AuthSigBytes []byte
76

77
        // Features is the list of protocol features supported by this node.
78
        Features *lnwire.RawFeatureVector
79

80
        // Color is the selected color for the node.
81
        Color color.RGBA
82

83
        // Alias is a nick-name for the node. The alias can be used to confirm
84
        // a node's identity or to serve as a short ID for an address book.
85
        Alias string
86

87
        // LastUpdate is the last time the vertex information for this node has
88
        // been updated.
89
        LastUpdate time.Time
90

91
        // ExtraOpaqueData is the set of data that was appended to this
92
        // message, some of which we may not actually know how to iterate or
93
        // parse. By holding onto this data, we ensure that we're able to
94
        // properly validate the set of signatures that cover these new fields,
95
        // and ensure we're able to make upgrades to the network in a forwards
96
        // compatible manner.
97
        ExtraOpaqueData []byte
98
}
99

100
// NewV1Node creates a new version 1 node from the passed fields.
101
func NewV1Node(pub route.Vertex, n *NodeV1Fields) *Node {
1,131✔
102
        return &Node{
1,131✔
103
                Version:      lnwire.GossipVersion1,
1,131✔
104
                PubKeyBytes:  pub,
1,131✔
105
                Addresses:    n.Addresses,
1,131✔
106
                AuthSigBytes: n.AuthSigBytes,
1,131✔
107
                Features: lnwire.NewFeatureVector(
1,131✔
108
                        n.Features, lnwire.Features,
1,131✔
109
                ),
1,131✔
110
                Color:           fn.Some(n.Color),
1,131✔
111
                Alias:           fn.Some(n.Alias),
1,131✔
112
                LastUpdate:      n.LastUpdate,
1,131✔
113
                ExtraOpaqueData: n.ExtraOpaqueData,
1,131✔
114
        }
1,131✔
115
}
1,131✔
116

117
// NodeV2Fields houses the fields that are specific to a version 2 node
118
// announcement.
119
type NodeV2Fields struct {
120
        // LastBlockHeight is the block height that timestamps the last update
121
        // we received for this node.
122
        LastBlockHeight uint32
123

124
        // Address is the TCP address this node is reachable over.
125
        Addresses []net.Addr
126

127
        // Color is the selected color for the node.
128
        Color fn.Option[color.RGBA]
129

130
        // Alias is a nick-name for the node. The alias can be used to confirm
131
        // a node's identity or to serve as a short ID for an address book.
132
        Alias fn.Option[string]
133

134
        // Signature is the schnorr signature under the advertised public key
135
        // which serves to authenticate the attributes announced by this node.
136
        Signature []byte
137

138
        // Features is the list of protocol features supported by this node.
139
        Features *lnwire.RawFeatureVector
140

141
        // ExtraSignedFields is a map of extra fields that are covered by the
142
        // node announcement's signature that we have not explicitly parsed.
143
        ExtraSignedFields map[uint64][]byte
144
}
145

146
// NewV2Node creates a new version 2 node from the passed fields.
NEW
147
func NewV2Node(pub route.Vertex, n *NodeV2Fields) *Node {
×
NEW
148
        return &Node{
×
NEW
149
                Version:      lnwire.GossipVersion2,
×
NEW
150
                PubKeyBytes:  pub,
×
NEW
151
                Addresses:    n.Addresses,
×
NEW
152
                AuthSigBytes: n.Signature,
×
NEW
153
                Features: lnwire.NewFeatureVector(
×
NEW
154
                        n.Features, lnwire.Features,
×
NEW
155
                ),
×
NEW
156
                LastBlockHeight:   n.LastBlockHeight,
×
NEW
157
                Color:             n.Color,
×
NEW
158
                Alias:             n.Alias,
×
NEW
159
                LastUpdate:        time.Unix(0, 0),
×
NEW
160
                ExtraSignedFields: n.ExtraSignedFields,
×
NEW
161
        }
×
NEW
162
}
×
163

164
// NewV1ShellNode creates a new shell version 1 node.
165
func NewV1ShellNode(pubKey route.Vertex) *Node {
9,547✔
166
        return NewShellNode(lnwire.GossipVersion1, pubKey)
9,547✔
167
}
9,547✔
168

169
// NewShellNode creates a new shell node with the given gossip version and
170
// public key.
171
func NewShellNode(v lnwire.GossipVersion, pubKey route.Vertex) *Node {
9,547✔
172
        return &Node{
9,547✔
173
                Version:     v,
9,547✔
174
                PubKeyBytes: pubKey,
9,547✔
175
                Features:    lnwire.EmptyFeatureVector(),
9,547✔
176
                LastUpdate:  time.Unix(0, 0),
9,547✔
177
        }
9,547✔
178
}
9,547✔
179

180
// HaveAnnouncement returns true if we have received a node announcement for
181
// this node. We determine this by checking if we have a signature for the
182
// announcement.
183
func (n *Node) HaveAnnouncement() bool {
1,182✔
184
        return len(n.AuthSigBytes) > 0
1,182✔
185
}
1,182✔
186

187
// PubKey is the node's long-term identity public key. This key will be used to
188
// authenticated any advertisements/updates sent by the node.
189
//
190
// NOTE: By having this method to access an attribute, we ensure we only need
191
// to fully deserialize the pubkey if absolutely necessary.
192
func (n *Node) PubKey() (*btcec.PublicKey, error) {
2,875✔
193
        if n.pubKey != nil {
4,397✔
194
                return n.pubKey, nil
1,522✔
195
        }
1,522✔
196

197
        key, err := btcec.ParsePubKey(n.PubKeyBytes[:])
1,356✔
198
        if err != nil {
1,356✔
199
                return nil, err
×
200
        }
×
201
        n.pubKey = key
1,356✔
202

1,356✔
203
        return key, nil
1,356✔
204
}
205

206
// NodeAnnouncement retrieves the latest node announcement of the node.
207
func (n *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
208
        error) {
18✔
209

18✔
210
        // Error out if we request the signed announcement, but we don't have
18✔
211
        // a signature for this announcement.
18✔
212
        if !n.HaveAnnouncement() && signed {
21✔
213
                return nil, fmt.Errorf("node does not have node announcement")
3✔
214
        }
3✔
215

216
        alias, err := lnwire.NewNodeAlias(n.Alias.UnwrapOr(""))
18✔
217
        if err != nil {
18✔
218
                return nil, err
×
219
        }
×
220

221
        nodeAnn := &lnwire.NodeAnnouncement1{
18✔
222
                Features:        n.Features.RawFeatureVector,
18✔
223
                NodeID:          n.PubKeyBytes,
18✔
224
                RGBColor:        n.Color.UnwrapOr(color.RGBA{}),
18✔
225
                Alias:           alias,
18✔
226
                Addresses:       n.Addresses,
18✔
227
                Timestamp:       uint32(n.LastUpdate.Unix()),
18✔
228
                ExtraOpaqueData: n.ExtraOpaqueData,
18✔
229
        }
18✔
230

18✔
231
        if !signed {
21✔
232
                return nodeAnn, nil
3✔
233
        }
3✔
234

235
        sig, err := lnwire.NewSigFromECDSARawSignature(n.AuthSigBytes)
18✔
236
        if err != nil {
18✔
237
                return nil, err
×
238
        }
×
239

240
        nodeAnn.Signature = sig
18✔
241

18✔
242
        return nodeAnn, nil
18✔
243
}
244

245
// NodeFromWireAnnouncement creates a Node instance from an
246
// lnwire.NodeAnnouncement1 message.
247
func NodeFromWireAnnouncement(msg *lnwire.NodeAnnouncement1) *Node {
20✔
248
        timestamp := time.Unix(int64(msg.Timestamp), 0)
20✔
249

20✔
250
        return NewV1Node(
20✔
251
                msg.NodeID,
20✔
252
                &NodeV1Fields{
20✔
253
                        LastUpdate:      timestamp,
20✔
254
                        Addresses:       msg.Addresses,
20✔
255
                        Alias:           msg.Alias.String(),
20✔
256
                        AuthSigBytes:    msg.Signature.ToSignatureBytes(),
20✔
257
                        Features:        msg.Features,
20✔
258
                        Color:           msg.RGBColor,
20✔
259
                        ExtraOpaqueData: msg.ExtraOpaqueData,
20✔
260
                },
20✔
261
        )
20✔
262
}
20✔
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

© 2026 Coveralls, Inc