From 2dc9ca43f365588286b0b2c2043407d781dedcd8 Mon Sep 17 00:00:00 2001 From: Abdullahi Yunus Date: Mon, 2 Jun 2025 14:53:12 +0100 Subject: [PATCH] itest: test for node ann persistence This commit adds an itest that verify the behaviour of correctly reusing persisted node ann configs across restarts. It also ensures that the node ann configs are applied using the correct hierarchy. --- itest/list_on_test.go | 4 + itest/lnd_channel_graph_test.go | 130 ++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index 7f9eaf574..aecbd1462 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -170,6 +170,10 @@ var allTestCases = []*lntest.TestCase{ Name: "update node announcement rpc", TestFunc: testUpdateNodeAnnouncement, }, + { + Name: "self node announcement persistence", + TestFunc: testSelfNodeAnnouncementPersistence, + }, { Name: "list payments", TestFunc: testListPayments, diff --git a/itest/lnd_channel_graph_test.go b/itest/lnd_channel_graph_test.go index 397a81e0e..6d30fe211 100644 --- a/itest/lnd_channel_graph_test.go +++ b/itest/lnd_channel_graph_test.go @@ -1,6 +1,7 @@ package itest import ( + "encoding/hex" "fmt" "strings" "testing" @@ -654,6 +655,135 @@ func testUpdateNodeAnnouncement(ht *lntest.HarnessTest) { dave.RPC.UpdateNodeAnnouncementErr(nodeAnnReq) } +// testSelfNodeAnnouncementPersistence tests that the node announcement configs +// are persisted correctly and reused when the node is restarted using the +// correct hierarchy (config > source node > defaults). +func testSelfNodeAnnouncementPersistence(ht *lntest.HarnessTest) { + // Start Alice with default node announcement options. + alice := ht.NewNode("Alice", nil) + + // assertAddrs is a helper function to assert that the node info + // contains the correct addresses. + assertAddrs := func(addrsFound []string, targetAddrs ...string) error { + addrs := make(map[string]struct{}, len(addrsFound)) + for _, addr := range addrsFound { + addr = strings.Split(addr, "@")[1] + addrs[addr] = struct{}{} + } + + for _, addr := range targetAddrs { + _, ok := addrs[addr] + if !ok { + return fmt.Errorf("address %v not found in "+ + "node announcement", addr) + } + } + + return nil + } + + // assertNodeInfo is a helper function to assert that the node info + // contains the correct values. + assertNodeInfo := func(resp *lnrpc.GetInfoResponse, expectedAlias, + expectedColor string, expectedAddrs ...string) { + + require.Equal(ht, expectedAlias, resp.Alias) + require.Equal(ht, expectedColor, resp.Color) + err := assertAddrs(resp.Uris, expectedAddrs...) + require.NoError(ht, err) + } + + // Get the node info and verify that the default values are used for + // alias and color. + resp := alice.RPC.GetInfo() + + // The alias should be the first 10 bytes of the serialized public key. + defaultAlias := hex.EncodeToString(alice.PubKey[:10]) + + // Assert that the default values are used for alias and color. + assertNodeInfo(resp, defaultAlias, "#3399ff") + + // Update the node announcement and set an alias, color, and addresses. + nodeAnnReq := &peersrpc.NodeAnnouncementUpdateRequest{ + Alias: "alice", + Color: "#eeeeee", + AddressUpdates: []*peersrpc.UpdateAddressAction{ + { + Action: peersrpc.UpdateAction_ADD, + Address: "192.168.1.10:8333", + }, + { + Action: peersrpc.UpdateAction_ADD, + Address: "192.168.1.11:8333", + }, + }, + } + + response := alice.RPC.UpdateNodeAnnouncement(nodeAnnReq) + + expectedOps := map[string]int{ + "alias": 1, + "color": 1, + "addresses": 2, + } + assertUpdateNodeAnnouncementResponse(ht, response, expectedOps) + + resp = alice.RPC.GetInfo() + assertNodeInfo( + resp, "alice", "#eeeeee", "192.168.1.10:8333", + "192.168.1.11:8333", + ) + + // Restart Alice. + ht.RestartNode(alice) + + // After restarting, the node info should contain the values that were + // set in the update request since the updated values take precedence + // over the default values. + resp = alice.RPC.GetInfo() + assertNodeInfo( + resp, "alice", "#eeeeee", "192.168.1.10:8333", + "192.168.1.11:8333", + ) + + // Test that we can still remove an address. + removeAddrReq := &peersrpc.NodeAnnouncementUpdateRequest{ + AddressUpdates: []*peersrpc.UpdateAddressAction{ + { + Action: peersrpc.UpdateAction_REMOVE, + Address: "192.168.1.10:8333", + }, + }, + } + response = alice.RPC.UpdateNodeAnnouncement(removeAddrReq) + expectedOps = map[string]int{ + "addresses": 1, + } + assertUpdateNodeAnnouncementResponse(ht, response, expectedOps) + + // Now we restart the node with custom values in the config. + lndArgs := []string{ + "--externalip=192.168.1.12:8333", + "--externalip=192.168.1.13:8333", + "--alias=alice-updated", + "--color=#ffffff", + } + ht.RestartNodeWithExtraArgs(alice, lndArgs) + + // Get the node info and verify that the values are the same as the + // ones we set in the config (and not the updated values). + // The addresses should be the same as the ones we set in the config + // plus the ones we set in the update request earlier. + resp = alice.RPC.GetInfo() + assertNodeInfo( + resp, "alice-updated", "#ffffff", "192.168.1.11:8333", + "192.168.1.12:8333", "192.168.1.13:8333", + ) + + // The address we removed earlier should not be present. + require.Error(ht, assertAddrs(resp.Uris, "192.168.1.10:8333")) +} + // assertSyncType asserts that the peer has an expected syncType. // // NOTE: only made for tests in this file.