Skip to content

Commit 5b1eaf9

Browse files
authored
Merge pull request #9474 from ellemouton/nodeAnnConversion
graph/db: correctly handle de(ser)ialisation of `models.LightningNode` opaque addresses
2 parents 457a245 + 16e2a48 commit 5b1eaf9

File tree

6 files changed

+128
-17
lines changed

6 files changed

+128
-17
lines changed

discovery/gossiper.go

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,21 +1982,7 @@ func (d *AuthenticatedGossiper) addNode(msg *lnwire.NodeAnnouncement,
19821982
err)
19831983
}
19841984

1985-
timestamp := time.Unix(int64(msg.Timestamp), 0)
1986-
features := lnwire.NewFeatureVector(msg.Features, lnwire.Features)
1987-
node := &models.LightningNode{
1988-
HaveNodeAnnouncement: true,
1989-
LastUpdate: timestamp,
1990-
Addresses: msg.Addresses,
1991-
PubKeyBytes: msg.NodeID,
1992-
Alias: msg.Alias.String(),
1993-
AuthSigBytes: msg.Signature.ToSignatureBytes(),
1994-
Features: features,
1995-
Color: msg.RGBColor,
1996-
ExtraOpaqueData: msg.ExtraOpaqueData,
1997-
}
1998-
1999-
return d.cfg.Graph.AddNode(node, op...)
1985+
return d.cfg.Graph.AddNode(models.NodeFromWireAnnouncement(msg), op...)
20001986
}
20011987

20021988
// isPremature decides whether a given network message has a block height+delta

docs/release-notes/release-notes-0.19.0.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/9322) that caused
6565
estimateroutefee to ignore the default payment timeout.
6666

67+
* [Fix a bug](https://github.com/lightningnetwork/lnd/pull/9474) where LND would
68+
fail to persist (and hence, propagate) node announcements containing address
69+
types (such as a DNS hostname) unknown to LND.
70+
6771
# New Features
6872

6973
* [Support](https://github.com/lightningnetwork/lnd/pull/8390) for

graph/db/addr.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"net"
99

10+
"github.com/lightningnetwork/lnd/lnwire"
1011
"github.com/lightningnetwork/lnd/tor"
1112
)
1213

@@ -26,6 +27,10 @@ const (
2627

2728
// v3OnionAddr denotes a version 3 Tor (prop224) onion service address.
2829
v3OnionAddr addressType = 3
30+
31+
// opaqueAddrs denotes an address (or a set of addresses) that LND was
32+
// not able to parse since LND is not yet aware of the address type.
33+
opaqueAddrs addressType = 4
2934
)
3035

3136
// encodeTCPAddr serializes a TCP address into its compact raw bytes
@@ -121,6 +126,27 @@ func encodeOnionAddr(w io.Writer, addr *tor.OnionAddr) error {
121126
return nil
122127
}
123128

129+
// encodeOpaqueAddrs serializes the lnwire.OpaqueAddrs type to a raw set of
130+
// bytes that we will persist.
131+
func encodeOpaqueAddrs(w io.Writer, addr *lnwire.OpaqueAddrs) error {
132+
// Write the type byte.
133+
if _, err := w.Write([]byte{byte(opaqueAddrs)}); err != nil {
134+
return err
135+
}
136+
137+
// Write the length of the payload.
138+
var l [2]byte
139+
binary.BigEndian.PutUint16(l[:], uint16(len(addr.Payload)))
140+
if _, err := w.Write(l[:]); err != nil {
141+
return err
142+
}
143+
144+
// Write the payload.
145+
_, err := w.Write(addr.Payload)
146+
147+
return err
148+
}
149+
124150
// DeserializeAddr reads the serialized raw representation of an address and
125151
// deserializes it into the actual address. This allows us to avoid address
126152
// resolution within the channeldb package.
@@ -147,6 +173,7 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) {
147173
IP: net.IP(ip[:]),
148174
Port: int(binary.BigEndian.Uint16(port[:])),
149175
}
176+
150177
case tcp6Addr:
151178
var ip [16]byte
152179
if _, err := r.Read(ip[:]); err != nil {
@@ -162,6 +189,7 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) {
162189
IP: net.IP(ip[:]),
163190
Port: int(binary.BigEndian.Uint16(port[:])),
164191
}
192+
165193
case v2OnionAddr:
166194
var h [tor.V2DecodedLen]byte
167195
if _, err := r.Read(h[:]); err != nil {
@@ -181,6 +209,7 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) {
181209
OnionService: onionService,
182210
Port: port,
183211
}
212+
184213
case v3OnionAddr:
185214
var h [tor.V3DecodedLen]byte
186215
if _, err := r.Read(h[:]); err != nil {
@@ -200,6 +229,24 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) {
200229
OnionService: onionService,
201230
Port: port,
202231
}
232+
233+
case opaqueAddrs:
234+
// Read the length of the payload.
235+
var l [2]byte
236+
if _, err := r.Read(l[:]); err != nil {
237+
return nil, err
238+
}
239+
240+
// Read the payload.
241+
payload := make([]byte, binary.BigEndian.Uint16(l[:]))
242+
if _, err := r.Read(payload); err != nil {
243+
return nil, err
244+
}
245+
246+
address = &lnwire.OpaqueAddrs{
247+
Payload: payload,
248+
}
249+
203250
default:
204251
return nil, ErrUnknownAddressType
205252
}
@@ -215,6 +262,8 @@ func SerializeAddr(w io.Writer, address net.Addr) error {
215262
return encodeTCPAddr(w, addr)
216263
case *tor.OnionAddr:
217264
return encodeOnionAddr(w, addr)
265+
case *lnwire.OpaqueAddrs:
266+
return encodeOpaqueAddrs(w, addr)
218267
default:
219268
return ErrUnknownAddressType
220269
}

graph/db/graph_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4063,3 +4063,56 @@ func TestClosedScid(t *testing.T) {
40634063
require.Nil(t, err)
40644064
require.True(t, exists)
40654065
}
4066+
4067+
// testNodeAnn is a serialized node announcement message which contains an
4068+
// address type (6) that LND is not aware of.
4069+
var testNodeAnn = "01012674c2e7ef68c73a086b7de2603f4ef1567358df84bb4edaa06c" +
4070+
"f2132965b14e2434faab04170f0089216accbd79188fa3d40dbb0438bd89782cae" +
4071+
"27cc656bf60007800088082a69a2625e7a2a024b9a1fa8e006f1e3937f65f66c40" +
4072+
"8e6da8e1ca728ea43222a7381df1cc449605024b9a424c554549524f4e2d76302e" +
4073+
"31312e307263332d362d67663963613934650000001d0180c7caa8260702240061" +
4074+
"80000000d0000000005cd2a001260706204c"
4075+
4076+
// TestLightningNodePersistence takes a raw serialized node announcement
4077+
// message, converts it to our internal models.LightningNode type, persists it
4078+
// to disk, reads it again and converts it back to a wire message and asserts
4079+
// that the two messages are equal.
4080+
func TestLightningNodePersistence(t *testing.T) {
4081+
t.Parallel()
4082+
4083+
// Create a new test graph instance.
4084+
graph, err := MakeTestGraph(t)
4085+
require.NoError(t, err)
4086+
4087+
nodeAnnBytes, err := hex.DecodeString(testNodeAnn)
4088+
require.NoError(t, err)
4089+
4090+
// Use the raw serialized node announcement message create an
4091+
// lnwire.NodeAnnouncement instance.
4092+
msg, err := lnwire.ReadMessage(bytes.NewBuffer(nodeAnnBytes), 0)
4093+
require.NoError(t, err)
4094+
na, ok := msg.(*lnwire.NodeAnnouncement)
4095+
require.True(t, ok)
4096+
4097+
// Convert the wire message to our internal node representation.
4098+
node := models.NodeFromWireAnnouncement(na)
4099+
4100+
// Persist the node to disk.
4101+
err = graph.AddLightningNode(node)
4102+
require.NoError(t, err)
4103+
4104+
// Read the node from disk.
4105+
diskNode, err := graph.FetchLightningNode(node.PubKeyBytes)
4106+
require.NoError(t, err)
4107+
4108+
// Convert it back to a wire message.
4109+
wireMsg, err := diskNode.NodeAnnouncement(true)
4110+
require.NoError(t, err)
4111+
4112+
// Encode it and compare against the original.
4113+
var b bytes.Buffer
4114+
_, err = lnwire.WriteMessage(&b, wireMsg, 0)
4115+
require.NoError(t, err)
4116+
4117+
require.Equal(t, nodeAnnBytes, b.Bytes())
4118+
}

graph/db/models/node.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,22 @@ func (l *LightningNode) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement,
131131

132132
return nodeAnn, nil
133133
}
134+
135+
// NodeFromWireAnnouncement creates a LightningNode instance from an
136+
// lnwire.NodeAnnouncement message.
137+
func NodeFromWireAnnouncement(msg *lnwire.NodeAnnouncement) *LightningNode {
138+
timestamp := time.Unix(int64(msg.Timestamp), 0)
139+
features := lnwire.NewFeatureVector(msg.Features, lnwire.Features)
140+
141+
return &LightningNode{
142+
HaveNodeAnnouncement: true,
143+
LastUpdate: timestamp,
144+
Addresses: msg.Addresses,
145+
PubKeyBytes: msg.NodeID,
146+
Alias: msg.Alias.String(),
147+
AuthSigBytes: msg.Signature.ToSignatureBytes(),
148+
Features: features,
149+
Color: msg.RGBColor,
150+
ExtraOpaqueData: msg.ExtraOpaqueData,
151+
}
152+
}

lnwire/lnwire_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ func TestChanUpdateChanFlags(t *testing.T) {
356356
}
357357
}
358358

359-
// TestDecodeUnknownAddressType shows that an unknown address type is currently
360-
// incorrectly dealt with.
359+
// TestDecodeUnknownAddressType shows that an unknown address type is correctly
360+
// decoded and encoded.
361361
func TestDecodeUnknownAddressType(t *testing.T) {
362362
// Add a normal, clearnet address.
363363
tcpAddr := &net.TCPAddr{

0 commit comments

Comments
 (0)