Skip to content

Commit 644be3e

Browse files
committed
graph/db/models: add node announcement serialization and address helpers
Add ToNodeAnnouncement which serializes a Node model back to its version-appropriate lnwire.NodeAnnouncement wire message. This enables round-tripping between the internal model and wire format. Also add V2NodeAddrs/SetV2NodeAddrs helpers for extracting and setting the typed address fields on v2 node announcements, and comprehensive tests for node wire round-tripping.
1 parent 6334689 commit 644be3e

2 files changed

Lines changed: 470 additions & 8 deletions

File tree

graph/db/models/node.go

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"github.com/lightningnetwork/lnd/fn/v2"
1111
"github.com/lightningnetwork/lnd/lnwire"
1212
"github.com/lightningnetwork/lnd/routing/route"
13+
"github.com/lightningnetwork/lnd/tlv"
14+
"github.com/lightningnetwork/lnd/tor"
1315
)
1416

1517
// Node represents an individual vertex/node within the channel graph.
@@ -22,6 +24,7 @@ type Node struct {
2224

2325
// PubKeyBytes is the raw bytes of the public key of the target node.
2426
PubKeyBytes [33]byte
27+
pubKey *btcec.PublicKey
2528

2629
// LastUpdate is the last time the vertex information for this node has
2730
// been updated.
@@ -185,20 +188,51 @@ func (n *Node) HaveAnnouncement() bool {
185188

186189
// PubKey is the node's long-term identity public key. This key will be used to
187190
// authenticated any advertisements/updates sent by the node.
191+
//
192+
// NOTE: By having this method to access the attribute, we ensure we only need
193+
// to fully deserialize the pubkey if absolutely necessary.
188194
func (n *Node) PubKey() (*btcec.PublicKey, error) {
189-
return btcec.ParsePubKey(n.PubKeyBytes[:])
195+
if n.pubKey != nil {
196+
return n.pubKey, nil
197+
}
198+
199+
key, err := btcec.ParsePubKey(n.PubKeyBytes[:])
200+
if err != nil {
201+
return nil, err
202+
}
203+
n.pubKey = key
204+
205+
return key, nil
190206
}
191207

192-
// NodeAnnouncement retrieves the latest node announcement of the node.
193-
func (n *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
208+
// NodeAnnouncement reconstructs the wire node announcement for this node.
209+
// If signed is true, the returned announcement will include the node's
210+
// signature. Returns an error if signed is true but no signature is stored.
211+
func (n *Node) NodeAnnouncement(signed bool) (lnwire.NodeAnnouncement,
194212
error) {
195213

196-
// Error out if we request the signed announcement, but we don't have
197-
// a signature for this announcement.
198-
if !n.HaveAnnouncement() && signed {
214+
if signed && !n.HaveAnnouncement() {
199215
return nil, fmt.Errorf("node does not have node announcement")
200216
}
201217

218+
switch n.Version {
219+
case lnwire.GossipVersion1:
220+
return n.toNodeAnnouncement1(signed)
221+
222+
case lnwire.GossipVersion2:
223+
return n.toNodeAnnouncement2(signed)
224+
225+
default:
226+
return nil, fmt.Errorf("unsupported node version: %d",
227+
n.Version)
228+
}
229+
}
230+
231+
// toNodeAnnouncement1 constructs a v1 node announcement from the node's
232+
// stored fields.
233+
func (n *Node) toNodeAnnouncement1(signed bool) (*lnwire.NodeAnnouncement1,
234+
error) {
235+
202236
alias, err := lnwire.NewNodeAlias(n.Alias.UnwrapOr(""))
203237
if err != nil {
204238
return nil, err
@@ -218,12 +252,97 @@ func (n *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
218252
return nodeAnn, nil
219253
}
220254

221-
sig, err := lnwire.NewSigFromECDSARawSignature(n.AuthSigBytes)
255+
nodeAnn.Signature, err = lnwire.NewSigFromECDSARawSignature(
256+
n.AuthSigBytes,
257+
)
222258
if err != nil {
223259
return nil, err
224260
}
225261

226-
nodeAnn.Signature = sig
262+
return nodeAnn, nil
263+
}
264+
265+
// toNodeAnnouncement2 constructs a v2 node announcement from the node's
266+
// stored fields.
267+
func (n *Node) toNodeAnnouncement2(signed bool) (*lnwire.NodeAnnouncement2,
268+
error) {
269+
270+
nodeAnn := &lnwire.NodeAnnouncement2{
271+
Features: tlv.NewRecordT[tlv.TlvType0](
272+
*n.Features.RawFeatureVector,
273+
),
274+
BlockHeight: tlv.NewPrimitiveRecord[tlv.TlvType2](
275+
n.LastBlockHeight,
276+
),
277+
NodeID: tlv.NewPrimitiveRecord[tlv.TlvType4, [33]byte](
278+
n.PubKeyBytes,
279+
),
280+
ExtraSignedFields: n.ExtraSignedFields,
281+
}
282+
283+
n.Alias.WhenSome(func(s string) {
284+
aliasRecord := tlv.ZeroRecordT[tlv.TlvType3, lnwire.NodeAlias2]()
285+
aliasRecord.Val = lnwire.NodeAlias2(s)
286+
nodeAnn.Alias = tlv.SomeRecordT(aliasRecord)
287+
})
288+
289+
n.Color.WhenSome(func(rgba color.RGBA) {
290+
colorRecord := tlv.ZeroRecordT[tlv.TlvType1, lnwire.Color]()
291+
colorRecord.Val = lnwire.Color(rgba)
292+
nodeAnn.Color = tlv.SomeRecordT(colorRecord)
293+
})
294+
295+
// Categorise addresses by type for the separate TLV fields.
296+
var (
297+
ipv4 lnwire.IPV4Addrs
298+
ipv6 lnwire.IPV6Addrs
299+
torV3 lnwire.TorV3Addrs
300+
)
301+
for _, addr := range n.Addresses {
302+
switch a := addr.(type) {
303+
case *net.TCPAddr:
304+
if a.IP.To4() != nil {
305+
ipv4 = append(ipv4, a)
306+
} else {
307+
ipv6 = append(ipv6, a)
308+
}
309+
310+
case *tor.OnionAddr:
311+
torV3 = append(torV3, a)
312+
313+
case *lnwire.DNSAddress:
314+
nodeAnn.DNSHostName = tlv.SomeRecordT(
315+
tlv.NewRecordT[tlv.TlvType11](*a),
316+
)
317+
}
318+
}
319+
if len(ipv4) > 0 {
320+
nodeAnn.IPV4Addrs = tlv.SomeRecordT(
321+
tlv.NewRecordT[tlv.TlvType5](ipv4),
322+
)
323+
}
324+
if len(ipv6) > 0 {
325+
nodeAnn.IPV6Addrs = tlv.SomeRecordT(
326+
tlv.NewRecordT[tlv.TlvType7](ipv6),
327+
)
328+
}
329+
if len(torV3) > 0 {
330+
nodeAnn.TorV3Addrs = tlv.SomeRecordT(
331+
tlv.NewRecordT[tlv.TlvType9](torV3),
332+
)
333+
}
334+
335+
if !signed {
336+
return nodeAnn, nil
337+
}
338+
339+
var err error
340+
nodeAnn.Signature.Val, err = lnwire.NewSigFromSchnorrRawSignature(
341+
n.AuthSigBytes,
342+
)
343+
if err != nil {
344+
return nil, err
345+
}
227346

228347
return nodeAnn, nil
229348
}

0 commit comments

Comments
 (0)