multi: remove HaveNodeAnnouncement field from Node

Remove the 2 sources of truth here. If we have a signature for the
node, then we have the announcement.
This commit is contained in:
Elle Mouton authored and yyforyongyu committed 2025-11-12 22:54:04 +08:00
1 parent a394938dfd
commit 8f205e2d1c
15 files changed
+154 -182

No files matched your search

+22 -26
View File
@@ -98,13 +98,12 @@ func TestIgnoreNodeAnnouncement(t *testing.T) {
pub := priv1.PubKey()
node := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0),
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
Alias: "node11",
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
LastUpdate: time.Unix(123, 0),
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
Alias: "node11",
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
}
copy(node.PubKeyBytes[:], pub.SerializeCompressed())
@@ -1085,13 +1084,12 @@ func TestIsStaleNode(t *testing.T) {
// With the node stub in the database, we'll add the fully node
// announcement to the database.
n1 := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: updateTimeStamp,
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
Alias: "node11",
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
LastUpdate: updateTimeStamp,
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
Alias: "node11",
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
}
copy(n1.PubKeyBytes[:], priv1.PubKey().SerializeCompressed())
if err := ctx.builder.AddNode(t.Context(), n1); err != nil {
@@ -1402,12 +1400,11 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
Alias: node.Alias,
Features: testFeatures,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
Alias: node.Alias,
Features: testFeatures,
}
copy(dbNode.PubKeyBytes[:], pubBytes)
@@ -1788,12 +1785,11 @@ func createTestGraphFromChannels(t *testing.T, useCache bool,
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
Alias: alias,
Features: features,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
Alias: alias,
Features: features,
}
copy(dbNode.PubKeyBytes[:], pubKey.SerializeCompressed())
+22 -26
View File
@@ -72,13 +72,12 @@ var (
func createNode(priv *btcec.PrivateKey) *models.Node {
pub := priv.PubKey().SerializeCompressed()
n := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: nextUpdateTime(),
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek" + hex.EncodeToString(pub),
Features: testFeatures,
Addresses: testAddrs,
AuthSigBytes: testSig.Serialize(),
LastUpdate: nextUpdateTime(),
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek" + hex.EncodeToString(pub),
Features: testFeatures,
Addresses: testAddrs,
}
copy(n.PubKeyBytes[:], priv.PubKey().SerializeCompressed())
@@ -107,15 +106,14 @@ func TestNodeInsertionAndDeletion(t *testing.T) {
nodeWithAddrs := func(addrs []net.Addr) *models.Node {
timeStamp++
return &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Unix(timeStamp, 0),
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek",
Features: testFeatures,
Addresses: addrs,
ExtraOpaqueData: []byte{1, 1, 1, 2, 2, 2, 2},
PubKeyBytes: testPub,
AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Unix(timeStamp, 0),
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek",
Features: testFeatures,
Addresses: addrs,
ExtraOpaqueData: []byte{1, 1, 1, 2, 2, 2, 2},
PubKeyBytes: testPub,
}
}
@@ -316,10 +314,9 @@ func TestPartialNode(t *testing.T) {
// The two nodes should match exactly! (with default values for
// LastUpdate and db set to satisfy compareNodes())
expectedNode1 := &models.Node{
HaveNodeAnnouncement: false,
LastUpdate: time.Unix(0, 0),
PubKeyBytes: pubKey1,
Features: lnwire.EmptyFeatureVector(),
LastUpdate: time.Unix(0, 0),
PubKeyBytes: pubKey1,
Features: lnwire.EmptyFeatureVector(),
}
compareNodes(t, expectedNode1, dbNode1)
@@ -330,10 +327,9 @@ func TestPartialNode(t *testing.T) {
// The two nodes should match exactly! (with default values for
// LastUpdate and db set to satisfy compareNodes())
expectedNode2 := &models.Node{
HaveNodeAnnouncement: false,
LastUpdate: time.Unix(0, 0),
PubKeyBytes: pubKey2,
Features: lnwire.EmptyFeatureVector(),
LastUpdate: time.Unix(0, 0),
PubKeyBytes: pubKey2,
Features: lnwire.EmptyFeatureVector(),
}
compareNodes(t, expectedNode2, dbNode2)
@@ -3782,11 +3778,11 @@ func TestAddChannelEdgeShellNodes(t *testing.T) {
// a shell node present.
node1, err := graph.FetchNode(ctx, node1.PubKeyBytes)
require.NoError(t, err, "unable to fetch node1")
require.True(t, node1.HaveNodeAnnouncement)
require.True(t, node1.HaveAnnouncement())
node2, err = graph.FetchNode(ctx, node2.PubKeyBytes)
require.NoError(t, err, "unable to fetch node2")
require.False(t, node2.HaveNodeAnnouncement)
require.False(t, node2.HaveAnnouncement())
// Show that attempting to add the channel again will result in an
// error.
+4 -12
View File
@@ -1206,8 +1206,7 @@ func (c *KVStore) addChannelEdge(tx kvdb.RwTx,
switch {
case errors.Is(node1Err, ErrGraphNodeNotFound):
node1Shell := models.Node{
PubKeyBytes: edge.NodeKey1Bytes,
HaveNodeAnnouncement: false,
PubKeyBytes: edge.NodeKey1Bytes,
}
err := addLightningNode(tx, &node1Shell)
if err != nil {
@@ -1222,8 +1221,7 @@ func (c *KVStore) addChannelEdge(tx kvdb.RwTx,
switch {
case errors.Is(node2Err, ErrGraphNodeNotFound):
node2Shell := models.Node{
PubKeyBytes: edge.NodeKey2Bytes,
HaveNodeAnnouncement: false,
PubKeyBytes: edge.NodeKey2Bytes,
}
err := addLightningNode(tx, &node2Shell)
if err != nil {
@@ -4369,7 +4367,7 @@ func putLightningNode(nodeBucket, aliasBucket, updateIndex kvdb.RwBucket,
// If we got a node announcement for this node, we will have the rest
// of the data available. If not we don't have more data to write.
if !node.HaveNodeAnnouncement {
if !node.HaveAnnouncement() {
// Write HaveNodeAnnouncement=0.
byteOrder.PutUint16(scratch[:2], 0)
if _, err := b.Write(scratch[:2]); err != nil {
@@ -4562,15 +4560,9 @@ func deserializeLightningNode(r io.Reader) (models.Node, error) {
}
hasNodeAnn := byteOrder.Uint16(scratch[:2])
if hasNodeAnn == 1 {
node.HaveNodeAnnouncement = true
} else {
node.HaveNodeAnnouncement = false
}
// The rest of the data is optional, and will only be there if we got a
// node announcement for this node.
if !node.HaveNodeAnnouncement {
if hasNodeAnn == 0 {
return node, nil
}
+32 -29
View File
@@ -19,11 +19,6 @@ type Node struct {
PubKeyBytes [33]byte
pubKey *btcec.PublicKey
// HaveNodeAnnouncement indicates whether we received a node
// announcement for this particular node. If true, the remaining fields
// will be set, if false only the PubKey is known for this node.
HaveNodeAnnouncement bool
// LastUpdate is the last time the vertex information for this node has
// been updated.
LastUpdate time.Time
@@ -54,53 +49,62 @@ type Node struct {
ExtraOpaqueData []byte
}
// HaveAnnouncement returns true if we have received a node announcement for
// this node. We determine this by checking if we have a signature for the
// announcement.
func (n *Node) HaveAnnouncement() bool {
return len(n.AuthSigBytes) > 0
}
// PubKey is the node's long-term identity public key. This key will be used to
// authenticated any advertisements/updates sent by the node.
//
// NOTE: By having this method to access an attribute, we ensure we only need
// to fully deserialize the pubkey if absolutely necessary.
func (l *Node) PubKey() (*btcec.PublicKey, error) {
if l.pubKey != nil {
return l.pubKey, nil
func (n *Node) PubKey() (*btcec.PublicKey, error) {
if n.pubKey != nil {
return n.pubKey, nil
}
key, err := btcec.ParsePubKey(l.PubKeyBytes[:])
key, err := btcec.ParsePubKey(n.PubKeyBytes[:])
if err != nil {
return nil, err
}
l.pubKey = key
n.pubKey = key
return key, nil
}
// NodeAnnouncement retrieves the latest node announcement of the node.
func (l *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
func (n *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1,
error) {
if !l.HaveNodeAnnouncement {
// Error out if we request the signed announcement, but we don't have
// a signature for this announcement.
if !n.HaveAnnouncement() && signed {
return nil, fmt.Errorf("node does not have node announcement")
}
alias, err := lnwire.NewNodeAlias(l.Alias)
alias, err := lnwire.NewNodeAlias(n.Alias)
if err != nil {
return nil, err
}
nodeAnn := &lnwire.NodeAnnouncement1{
Features: l.Features.RawFeatureVector,
NodeID: l.PubKeyBytes,
RGBColor: l.Color,
Features: n.Features.RawFeatureVector,
NodeID: n.PubKeyBytes,
RGBColor: n.Color,
Alias: alias,
Addresses: l.Addresses,
Timestamp: uint32(l.LastUpdate.Unix()),
ExtraOpaqueData: l.ExtraOpaqueData,
Addresses: n.Addresses,
Timestamp: uint32(n.LastUpdate.Unix()),
ExtraOpaqueData: n.ExtraOpaqueData,
}
if !signed {
return nodeAnn, nil
}
sig, err := lnwire.NewSigFromECDSARawSignature(l.AuthSigBytes)
sig, err := lnwire.NewSigFromECDSARawSignature(n.AuthSigBytes)
if err != nil {
return nil, err
}
@@ -117,14 +121,13 @@ func NodeFromWireAnnouncement(msg *lnwire.NodeAnnouncement1) *Node {
features := lnwire.NewFeatureVector(msg.Features, lnwire.Features)
return &Node{
HaveNodeAnnouncement: true,
LastUpdate: timestamp,
Addresses: msg.Addresses,
PubKeyBytes: msg.NodeID,
Alias: msg.Alias.String(),
AuthSigBytes: msg.Signature.ToSignatureBytes(),
Features: features,
Color: msg.RGBColor,
ExtraOpaqueData: msg.ExtraOpaqueData,
LastUpdate: timestamp,
Addresses: msg.Addresses,
PubKeyBytes: msg.NodeID,
Alias: msg.Alias.String(),
AuthSigBytes: msg.Signature.ToSignatureBytes(),
Features: features,
Color: msg.RGBColor,
ExtraOpaqueData: msg.ExtraOpaqueData,
}
}
+2 -2
View File
@@ -1449,7 +1449,7 @@ func insertNodeSQLMig(ctx context.Context, db SQLQueries,
PubKey: node.PubKeyBytes[:],
}
if node.HaveNodeAnnouncement {
if node.HaveAnnouncement() {
params.LastUpdate = sqldb.SQLInt64(node.LastUpdate.Unix())
params.Color = sqldb.SQLStrValid(EncodeHexColor(node.Color))
params.Alias = sqldb.SQLStrValid(node.Alias)
@@ -1463,7 +1463,7 @@ func insertNodeSQLMig(ctx context.Context, db SQLQueries,
}
// We can exit here if we don't have the announcement yet.
if !node.HaveNodeAnnouncement {
if !node.HaveAnnouncement() {
return nodeID, nil
}
+16 -20
View File
@@ -385,8 +385,7 @@ func TestMigrateGraphToSQL(t *testing.T) {
// node be set. So that is the first object
// we will write.
&models.Node{
HaveNodeAnnouncement: false,
PubKeyBytes: testPub,
PubKeyBytes: testPub,
},
// Now we add some block heights to prune
// the graph at.
@@ -748,15 +747,14 @@ type testNodeOpt func(*models.Node)
// functional options can be used to modify the node's attributes.
func makeTestNode(t *testing.T, opts ...testNodeOpt) *models.Node {
n := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSigBytes,
LastUpdate: testTime,
Color: testColor,
Alias: "kek",
Features: testFeatures,
Addresses: testAddrs,
ExtraOpaqueData: testExtraData,
PubKeyBytes: genPubKey(t),
AuthSigBytes: testSigBytes,
LastUpdate: testTime,
Color: testColor,
Alias: "kek",
Features: testFeatures,
Addresses: testAddrs,
ExtraOpaqueData: testExtraData,
PubKeyBytes: genPubKey(t),
}
for _, opt := range opts {
@@ -777,10 +775,9 @@ func makeTestShellNode(t *testing.T,
opts ...testNodeOpt) *models.Node {
n := &models.Node{
HaveNodeAnnouncement: false,
PubKeyBytes: genPubKey(t),
Features: testEmptyFeatures,
LastUpdate: time.Unix(0, 0),
PubKeyBytes: genPubKey(t),
Features: testEmptyFeatures,
LastUpdate: time.Unix(0, 0),
}
for _, opt := range opts {
@@ -1817,11 +1814,10 @@ func genRandomNode(t *rapid.T) *models.Node {
}
node := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: sigBytes,
LastUpdate: randTime,
Color: randColor,
Alias: alias.String(),
AuthSigBytes: sigBytes,
LastUpdate: randTime,
Color: randColor,
Alias: alias.String(),
Features: lnwire.NewFeatureVector(
features, lnwire.Features,
),
+2 -3
View File
@@ -3495,7 +3495,6 @@ func buildNodeWithBatchData(dbNode sqlc.GraphNode,
return node, nil
}
node.HaveNodeAnnouncement = true
node.AuthSigBytes = dbNode.Signature
node.Alias = dbNode.Alias.String
node.LastUpdate = time.Unix(dbNode.LastUpdate.Int64, 0)
@@ -3608,7 +3607,7 @@ func upsertNode(ctx context.Context, db SQLQueries,
PubKey: node.PubKeyBytes[:],
}
if node.HaveNodeAnnouncement {
if node.HaveAnnouncement() {
params.LastUpdate = sqldb.SQLInt64(node.LastUpdate.Unix())
params.Color = sqldb.SQLStrValid(EncodeHexColor(node.Color))
params.Alias = sqldb.SQLStrValid(node.Alias)
@@ -3622,7 +3621,7 @@ func upsertNode(ctx context.Context, db SQLQueries,
}
// We can exit here if we don't have the announcement yet.
if !node.HaveNodeAnnouncement {
if !node.HaveAnnouncement() {
return nodeID, nil
}
+6 -7
View File
@@ -84,13 +84,12 @@ func createTestNode(t *testing.T) *models.Node {
pub := priv.PubKey().SerializeCompressed()
n := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(updateTime, 0),
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek" + hex.EncodeToString(pub),
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
LastUpdate: time.Unix(updateTime, 0),
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
Alias: "kek" + hex.EncodeToString(pub),
AuthSigBytes: testSig.Serialize(),
Features: testFeatures,
}
copy(n.PubKeyBytes[:], pub)