From 71b2338d531409f2baa66f8a1529ab04923862f7 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 5 Feb 2025 08:29:25 +0200 Subject: [PATCH] graph/db: de(ser)ialise opaque node addrs In this commit, we fix the bug demonstrated in the prior commit. We correctly handle the persistence of lnwire.OpaqueAddrs. --- graph/db/addr.go | 49 ++++++++++++++++++++++++++++++++++++++++++ graph/db/graph_test.go | 29 +++++++++++++++++-------- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/graph/db/addr.go b/graph/db/addr.go index f99413158..c68039a26 100644 --- a/graph/db/addr.go +++ b/graph/db/addr.go @@ -7,6 +7,7 @@ import ( "io" "net" + "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/tor" ) @@ -26,6 +27,10 @@ const ( // v3OnionAddr denotes a version 3 Tor (prop224) onion service address. v3OnionAddr addressType = 3 + + // opaqueAddrs denotes an address (or a set of addresses) that LND was + // not able to parse since LND is not yet aware of the address type. + opaqueAddrs addressType = 4 ) // encodeTCPAddr serializes a TCP address into its compact raw bytes @@ -121,6 +126,27 @@ func encodeOnionAddr(w io.Writer, addr *tor.OnionAddr) error { return nil } +// encodeOpaqueAddrs serializes the lnwire.OpaqueAddrs type to a raw set of +// bytes that we will persist. +func encodeOpaqueAddrs(w io.Writer, addr *lnwire.OpaqueAddrs) error { + // Write the type byte. + if _, err := w.Write([]byte{byte(opaqueAddrs)}); err != nil { + return err + } + + // Write the length of the payload. + var l [2]byte + binary.BigEndian.PutUint16(l[:], uint16(len(addr.Payload))) + if _, err := w.Write(l[:]); err != nil { + return err + } + + // Write the payload. + _, err := w.Write(addr.Payload) + + return err +} + // DeserializeAddr reads the serialized raw representation of an address and // deserializes it into the actual address. This allows us to avoid address // resolution within the channeldb package. @@ -147,6 +173,7 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) { IP: net.IP(ip[:]), Port: int(binary.BigEndian.Uint16(port[:])), } + case tcp6Addr: var ip [16]byte if _, err := r.Read(ip[:]); err != nil { @@ -162,6 +189,7 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) { IP: net.IP(ip[:]), Port: int(binary.BigEndian.Uint16(port[:])), } + case v2OnionAddr: var h [tor.V2DecodedLen]byte if _, err := r.Read(h[:]); err != nil { @@ -181,6 +209,7 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) { OnionService: onionService, Port: port, } + case v3OnionAddr: var h [tor.V3DecodedLen]byte if _, err := r.Read(h[:]); err != nil { @@ -200,6 +229,24 @@ func DeserializeAddr(r io.Reader) (net.Addr, error) { OnionService: onionService, Port: port, } + + case opaqueAddrs: + // Read the length of the payload. + var l [2]byte + if _, err := r.Read(l[:]); err != nil { + return nil, err + } + + // Read the payload. + payload := make([]byte, binary.BigEndian.Uint16(l[:])) + if _, err := r.Read(payload); err != nil { + return nil, err + } + + address = &lnwire.OpaqueAddrs{ + Payload: payload, + } + default: return nil, ErrUnknownAddressType } @@ -215,6 +262,8 @@ func SerializeAddr(w io.Writer, address net.Addr) error { return encodeTCPAddr(w, addr) case *tor.OnionAddr: return encodeOnionAddr(w, addr) + case *lnwire.OpaqueAddrs: + return encodeOpaqueAddrs(w, addr) default: return ErrUnknownAddressType } diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index 774639829..d048cdafd 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -4074,12 +4074,9 @@ var testNodeAnn = "01012674c2e7ef68c73a086b7de2603f4ef1567358df84bb4edaa06c" + "80000000d0000000005cd2a001260706204c" // TestLightningNodePersistence takes a raw serialized node announcement -// message, converts it to our internal models.LightningNode type and attempts -// to persist this to disk. -// -// NOTE: Currently, this tests demonstrates that we are _unable_ to do this if -// the node announcement has an address type unknown to LND. This will be fixed -// in an upcoming commit. +// message, converts it to our internal models.LightningNode type, persists it +// to disk, reads it again and converts it back to a wire message and asserts +// that the two messages are equal. func TestLightningNodePersistence(t *testing.T) { t.Parallel() @@ -4100,8 +4097,22 @@ func TestLightningNodePersistence(t *testing.T) { // Convert the wire message to our internal node representation. node := models.NodeFromWireAnnouncement(na) - // Attempt to persist the node to disk. This currently fails due to the - // unknown address type. + // Persist the node to disk. err = graph.AddLightningNode(node) - require.ErrorContains(t, err, "address type cannot be resolved") + require.NoError(t, err) + + // Read the node from disk. + diskNode, err := graph.FetchLightningNode(node.PubKeyBytes) + require.NoError(t, err) + + // Convert it back to a wire message. + wireMsg, err := diskNode.NodeAnnouncement(true) + require.NoError(t, err) + + // Encode it and compare against the original. + var b bytes.Buffer + _, err = lnwire.WriteMessage(&b, wireMsg, 0) + require.NoError(t, err) + + require.Equal(t, nodeAnnBytes, b.Bytes()) }