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
+38 -66

No files matched your search

-3
View File
@@ -418,7 +418,6 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey,
fallthrough
case errors.Is(err, graphdb.ErrGraphNotFound):
graphNode := &models.Node{
HaveNodeAnnouncement: true,
Addresses: []net.Addr{&net.TCPAddr{
IP: bytes.Repeat(
[]byte("a"), 16,
@@ -451,7 +450,6 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey,
return nil, err
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
Addresses: []net.Addr{
&net.TCPAddr{
IP: bytes.Repeat([]byte("a"), 16),
@@ -552,7 +550,6 @@ func (d *testDBGraph) addRandNode() (*btcec.PublicKey, error) {
return nil, err
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
Addresses: []net.Addr{
&net.TCPAddr{
IP: bytes.Repeat([]byte("a"), 16),
-1
View File
@@ -812,7 +812,6 @@ func createNode(priv *btcec.PrivateKey) *models.Node {
pub := priv.PubKey().SerializeCompressed()
n := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: time.Unix(updateTime, 0),
Color: color.RGBA{1, 2, 3, 0},
+2 -2
View File
@@ -295,7 +295,7 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
// If this edge has a validated node announcement, that
// we haven't yet sent, then we'll send that as well.
nodePub := channel.Node2.PubKeyBytes
hasNodeAnn := channel.Node2.HaveNodeAnnouncement
hasNodeAnn := channel.Node2.HaveAnnouncement()
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
nodeAnn, err := channel.Node2.NodeAnnouncement(
true,
@@ -321,7 +321,7 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
// If this edge has a validated node announcement, that
// we haven't yet sent, then we'll send that as well.
nodePub := channel.Node1.PubKeyBytes
hasNodeAnn := channel.Node1.HaveNodeAnnouncement
hasNodeAnn := channel.Node1.HaveAnnouncement()
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
nodeAnn, err := channel.Node1.NodeAnnouncement(
true,
-4
View File
@@ -98,7 +98,6 @@ 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},
@@ -1085,7 +1084,6 @@ 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},
@@ -1402,7 +1400,6 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
@@ -1788,7 +1785,6 @@ func createTestGraphFromChannels(t *testing.T, useCache bool,
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
+2 -6
View File
@@ -72,7 +72,6 @@ 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},
@@ -107,7 +106,6 @@ 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},
@@ -316,7 +314,6 @@ 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(),
@@ -330,7 +327,6 @@ 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(),
@@ -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.
+2 -10
View File
@@ -1207,7 +1207,6 @@ func (c *KVStore) addChannelEdge(tx kvdb.RwTx,
case errors.Is(node1Err, ErrGraphNodeNotFound):
node1Shell := models.Node{
PubKeyBytes: edge.NodeKey1Bytes,
HaveNodeAnnouncement: false,
}
err := addLightningNode(tx, &node1Shell)
if err != nil {
@@ -1223,7 +1222,6 @@ func (c *KVStore) addChannelEdge(tx kvdb.RwTx,
case errors.Is(node2Err, ErrGraphNodeNotFound):
node2Shell := models.Node{
PubKeyBytes: edge.NodeKey2Bytes,
HaveNodeAnnouncement: false,
}
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
}
+24 -21
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,7 +121,6 @@ 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,
+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
}
-4
View File
@@ -385,7 +385,6 @@ func TestMigrateGraphToSQL(t *testing.T) {
// node be set. So that is the first object
// we will write.
&models.Node{
HaveNodeAnnouncement: false,
PubKeyBytes: testPub,
},
// Now we add some block heights to prune
@@ -748,7 +747,6 @@ 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,
@@ -777,7 +775,6 @@ func makeTestShellNode(t *testing.T,
opts ...testNodeOpt) *models.Node {
n := &models.Node{
HaveNodeAnnouncement: false,
PubKeyBytes: genPubKey(t),
Features: testEmptyFeatures,
LastUpdate: time.Unix(0, 0),
@@ -1817,7 +1814,6 @@ func genRandomNode(t *rapid.T) *models.Node {
}
node := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: sigBytes,
LastUpdate: randTime,
Color: randColor,
+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
}
-1
View File
@@ -84,7 +84,6 @@ 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},
+4 -1
View File
@@ -227,11 +227,14 @@ func (s *Server) ImportGraph(ctx context.Context,
var err error
for _, rpcNode := range graph.Nodes {
node := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(
int64(rpcNode.LastUpdate), 0,
),
Alias: rpcNode.Alias,
// NOTE: this is a workaround to ensure that
// HaveAnnouncement() returns true so that the other
// fields are properly persisted. However,
AuthSigBytes: []byte{0},
}
node.PubKeyBytes, err = parsePubKey(rpcNode.PubKey)
-2
View File
@@ -229,7 +229,6 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
@@ -566,7 +565,6 @@ func createTestGraphFromChannels(t *testing.T, useCache bool,
}
dbNode := &models.Node{
HaveNodeAnnouncement: true,
AuthSigBytes: testSig.Serialize(),
LastUpdate: testTime,
Addresses: testAddrs,
-3
View File
@@ -193,7 +193,6 @@ func createTestNode() (*models.Node, error) {
pub := priv.PubKey().SerializeCompressed()
n := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(updateTime, 0),
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
@@ -2872,7 +2871,6 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// Now check that we can update the node info for the partial node
// without messing up the channel graph.
n1 := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0),
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
@@ -2885,7 +2883,6 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
require.NoError(t, ctx.graph.AddNode(ctxb, n1))
n2 := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(123, 0),
Addresses: testAddrs,
Color: color.RGBA{1, 2, 3, 0},
-3
View File
@@ -3300,7 +3300,6 @@ func (s *server) createNewHiddenService(ctx context.Context) error {
// Finally, we'll update the on-disk version of our announcement so it
// will eventually propagate to nodes in the network.
selfNode := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: time.Unix(int64(newNodeAnn.Timestamp), 0),
Addresses: newNodeAnn.Addresses,
Alias: newNodeAnn.Alias.String(),
@@ -3424,7 +3423,6 @@ func (s *server) updateAndBroadcastSelfNode(ctx context.Context,
return fmt.Errorf("unable to get current source node: %w", err)
}
selfNode.HaveNodeAnnouncement = true
selfNode.LastUpdate = time.Unix(int64(newNodeAnn.Timestamp), 0)
selfNode.Addresses = newNodeAnn.Addresses
selfNode.Alias = newNodeAnn.Alias.String()
@@ -5646,7 +5644,6 @@ func (s *server) setSelfNode(ctx context.Context, nodePub route.Vertex,
// TODO(abdulkbk): potentially find a way to use the source node's
// features in the self node.
selfNode := &models.Node{
HaveNodeAnnouncement: true,
LastUpdate: nodeLastUpdate,
Addresses: addrs,
Alias: nodeAlias.String(),