diff --git a/lnrpc/peersrpc/peers_server.go b/lnrpc/peersrpc/peers_server.go index 9ca6f437a..aae96bc1b 100644 --- a/lnrpc/peersrpc/peers_server.go +++ b/lnrpc/peersrpc/peers_server.go @@ -9,6 +9,7 @@ import ( "sync/atomic" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/netann" @@ -177,7 +178,25 @@ func (s *Server) UpdateNodeAnnouncement(_ context.Context, // TODO(positiveblue): apply feature bit modifications - // TODO(positiveblue): apply color modifications + if req.Color != "" { + color, err := lncfg.ParseHexColor(req.Color) + if err != nil { + return nil, fmt.Errorf("unable to parse color: %v", err) + } + + if color != currentNodeAnn.RGBColor { + resp.Ops = append(resp.Ops, &lnrpc.Op{ + Entity: "color", + Actions: []string{ + fmt.Sprintf("changed to %v", color), + }, + }) + nodeModifiers = append( + nodeModifiers, + netann.NodeAnnSetColor(color), + ) + } + } if req.Alias != "" { alias, err := lnwire.NewNodeAlias(req.Alias) diff --git a/lntest/itest/assertions.go b/lntest/itest/assertions.go index 2110d6e9e..01fe6b211 100644 --- a/lntest/itest/assertions.go +++ b/lntest/itest/assertions.go @@ -1862,6 +1862,9 @@ func assertAnchorOutputLost(t *harnessTest, node *lntest.HarnessNode, func assertNodeAnnouncement(t *harnessTest, n1, n2 *lnrpc.NodeUpdate) { // Alias should match. require.Equal(t.t, n1.Alias, n2.Alias, "alias don't match") + + // Color should match. + require.Equal(t.t, n1.Color, n2.Color, "color don't match") } // assertUpdateNodeAnnouncementResponse is a helper function to assert diff --git a/lntest/itest/lnd_channel_graph_test.go b/lntest/itest/lnd_channel_graph_test.go index 9910c62d1..7c19883e0 100644 --- a/lntest/itest/lnd_channel_graph_test.go +++ b/lntest/itest/lnd_channel_graph_test.go @@ -821,6 +821,7 @@ func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) { defaultDaveNodeAnn := &lnrpc.NodeUpdate{ Alias: resp.Alias, + Color: resp.Color, } // Dave must have an open channel before he can send a node @@ -866,15 +867,18 @@ func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) { // Update Node. newAlias := "new-alias" + newColor := "#2288ee" nodeAnnReq := &peersrpc.NodeAnnouncementUpdateRequest{ Alias: newAlias, + Color: newColor, } response, err := dave.UpdateNodeAnnouncement(ctxt, nodeAnnReq) require.NoError(t.t, err, "unable to update dave's node announcement") expectedOps := map[string]int{ + "color": 1, "alias": 1, } assertUpdateNodeAnnouncementResponse(t, response, expectedOps) @@ -883,6 +887,7 @@ func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) { // the requested color, requested alias and the new added addresses. newDaveNodeAnn := &lnrpc.NodeUpdate{ Alias: newAlias, + Color: newColor, } // We'll then wait for Alice to receive dave's node announcement diff --git a/netann/node_announcement.go b/netann/node_announcement.go index df13ca1b6..48dc8411e 100644 --- a/netann/node_announcement.go +++ b/netann/node_announcement.go @@ -1,6 +1,7 @@ package netann import ( + "image/color" "net" "time" @@ -29,6 +30,14 @@ func NodeAnnSetAddrs(addrs []net.Addr) func(*lnwire.NodeAnnouncement) { } } +// NodeAnnSetColor is a functional option that sets the color of the +// given node announcment. +func NodeAnnSetColor(newColor color.RGBA) func(*lnwire.NodeAnnouncement) { + return func(nodeAnn *lnwire.NodeAnnouncement) { + nodeAnn.RGBColor = newColor + } +} + // NodeAnnSetTimestamp is a functional option that sets the timestamp of the // announcement to the current time, or increments it if the timestamp is // already in the future.