mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-12 09:52:14 +02:00
lnrpc/peers: handle alias changes in updateNodeAnnouncement
This commit is contained in:
parent
e4e0935816
commit
ce4813940d
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||||
@ -168,7 +169,7 @@ func (s *Server) UpdateNodeAnnouncement(_ context.Context,
|
|||||||
resp := &NodeAnnouncementUpdateResponse{}
|
resp := &NodeAnnouncementUpdateResponse{}
|
||||||
nodeModifiers := make([]netann.NodeAnnModifier, 0)
|
nodeModifiers := make([]netann.NodeAnnModifier, 0)
|
||||||
|
|
||||||
_, err := s.cfg.GetNodeAnnouncement()
|
currentNodeAnn, err := s.cfg.GetNodeAnnouncement()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to get current node "+
|
return nil, fmt.Errorf("unable to get current node "+
|
||||||
"announcement: %v", err)
|
"announcement: %v", err)
|
||||||
@ -178,7 +179,24 @@ func (s *Server) UpdateNodeAnnouncement(_ context.Context,
|
|||||||
|
|
||||||
// TODO(positiveblue): apply color modifications
|
// TODO(positiveblue): apply color modifications
|
||||||
|
|
||||||
// TODO(positiveblue): apply alias modifications
|
if req.Alias != "" {
|
||||||
|
alias, err := lnwire.NewNodeAlias(req.Alias)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid alias value: %v", err)
|
||||||
|
}
|
||||||
|
if alias != currentNodeAnn.Alias {
|
||||||
|
resp.Ops = append(resp.Ops, &lnrpc.Op{
|
||||||
|
Entity: "alias",
|
||||||
|
Actions: []string{
|
||||||
|
fmt.Sprintf("changed to %v", alias),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
nodeModifiers = append(
|
||||||
|
nodeModifiers,
|
||||||
|
netann.NodeAnnSetAlias(alias),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(positiveblue): apply addresses modifications
|
// TODO(positiveblue): apply addresses modifications
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc/peersrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
@ -1856,3 +1857,33 @@ func assertAnchorOutputLost(t *harnessTest, node *lntest.HarnessNode,
|
|||||||
}, defaultTimeout)
|
}, defaultTimeout)
|
||||||
require.NoError(t.t, err, "anchor doesn't show as being lost")
|
require.NoError(t.t, err, "anchor doesn't show as being lost")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assertNodeAnnouncement compares that two node announcements match.
|
||||||
|
func assertNodeAnnouncement(t *harnessTest, n1, n2 *lnrpc.NodeUpdate) {
|
||||||
|
// Alias should match.
|
||||||
|
require.Equal(t.t, n1.Alias, n2.Alias, "alias don't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertUpdateNodeAnnouncementResponse is a helper function to assert
|
||||||
|
// the response expected values.
|
||||||
|
func assertUpdateNodeAnnouncementResponse(t *harnessTest,
|
||||||
|
response *peersrpc.NodeAnnouncementUpdateResponse,
|
||||||
|
expectedOps map[string]int) {
|
||||||
|
|
||||||
|
require.Equal(
|
||||||
|
t.t, len(response.Ops), len(expectedOps),
|
||||||
|
"unexpected number of Ops updating dave's node announcement",
|
||||||
|
)
|
||||||
|
|
||||||
|
ops := make(map[string]int, len(response.Ops))
|
||||||
|
for _, op := range response.Ops {
|
||||||
|
ops[op.Entity] = len(op.Actions)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range expectedOps {
|
||||||
|
if v != ops[k] {
|
||||||
|
t.Fatalf("unexpected number of actions for operation "+
|
||||||
|
"%s: got %d wanted %d", k, ops[k], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -769,16 +770,80 @@ func subscribeGraphNotifications(ctxb context.Context, t *harnessTest,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// waitForNodeAnnUpdates monitors the nodeAnnUpdates until we get one for
|
||||||
|
// the expected node and asserts that has the expected information.
|
||||||
|
func waitForNodeAnnUpdates(graphSub graphSubscription, nodePubKey string,
|
||||||
|
expectedUpdate *lnrpc.NodeUpdate, t *harnessTest) {
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case graphUpdate := <-graphSub.updateChan:
|
||||||
|
for _, update := range graphUpdate.NodeUpdates {
|
||||||
|
if update.IdentityKey == nodePubKey {
|
||||||
|
assertNodeAnnouncement(
|
||||||
|
t, update, expectedUpdate,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case err := <-graphSub.errChan:
|
||||||
|
t.Fatalf("unable to recv graph update: %v", err)
|
||||||
|
case <-time.After(defaultTimeout):
|
||||||
|
t.Fatalf("did not receive node ann update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// testUpdateNodeAnnouncement ensures that the RPC endpoint validates
|
// testUpdateNodeAnnouncement ensures that the RPC endpoint validates
|
||||||
// the requests correctly and that the new node announcement is brodcasted
|
// the requests correctly and that the new node announcement is brodcasted
|
||||||
// with the right information after updating our node.
|
// with the right information after updating our node.
|
||||||
func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
|
func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
// context timeout for the whole test.
|
||||||
|
ctxt, cancel := context.WithTimeout(
|
||||||
|
context.Background(), defaultTimeout,
|
||||||
|
)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Launch notification clients for alice, such that we can
|
||||||
|
// get notified when there are updates in the graph.
|
||||||
|
aliceSub := subscribeGraphNotifications(ctxt, t, net.Alice)
|
||||||
|
defer close(aliceSub.quit)
|
||||||
|
|
||||||
var lndArgs []string
|
var lndArgs []string
|
||||||
dave := net.NewNode(t.t, "Dave", lndArgs)
|
dave := net.NewNode(t.t, "Dave", lndArgs)
|
||||||
defer shutdownAndAssert(net, t, dave)
|
defer shutdownAndAssert(net, t, dave)
|
||||||
|
|
||||||
|
// Get dave default information so we can compare
|
||||||
|
// it lately with the brodcasted updates.
|
||||||
|
nodeInfoReq := &lnrpc.GetInfoRequest{}
|
||||||
|
resp, err := dave.GetInfo(ctxt, nodeInfoReq)
|
||||||
|
require.NoError(t.t, err, "unable to get dave's information")
|
||||||
|
|
||||||
|
defaultDaveNodeAnn := &lnrpc.NodeUpdate{
|
||||||
|
Alias: resp.Alias,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dave must have an open channel before he can send a node
|
||||||
|
// announcement, so we open a channel with Bob.
|
||||||
|
net.ConnectNodes(t.t, net.Bob, dave)
|
||||||
|
|
||||||
|
// Go ahead and open a channel between Bob and Dave. This
|
||||||
|
// ensures that Alice receives the node announcement from Bob as part of
|
||||||
|
// the announcement broadcast.
|
||||||
|
chanPoint := openChannelAndAssert(
|
||||||
|
t, net, net.Bob, dave,
|
||||||
|
lntest.OpenChannelParams{
|
||||||
|
Amt: 1000000,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t.t, err, "unexpected error opening a channel")
|
||||||
|
|
||||||
|
// Wait for Alice to receive dave's node announcement with the default
|
||||||
|
// values.
|
||||||
|
waitForNodeAnnUpdates(
|
||||||
|
aliceSub, dave.PubKeyStr, defaultDaveNodeAnn, t,
|
||||||
|
)
|
||||||
|
|
||||||
// We cannot differentiate between requests with Alias = "" and requests
|
// We cannot differentiate between requests with Alias = "" and requests
|
||||||
// that do not provide that field. If a user sets Alias = "" in the request
|
// that do not provide that field. If a user sets Alias = "" in the request
|
||||||
// the field will simply be ignored. The request must fail because no
|
// the field will simply be ignored. The request must fail because no
|
||||||
@ -786,9 +851,46 @@ func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
invalidNodeAnnReq := &peersrpc.NodeAnnouncementUpdateRequest{
|
invalidNodeAnnReq := &peersrpc.NodeAnnouncementUpdateRequest{
|
||||||
Alias: "",
|
Alias: "",
|
||||||
}
|
}
|
||||||
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
_, err := dave.UpdateNodeAnnouncement(ctxt, invalidNodeAnnReq)
|
_, err = dave.UpdateNodeAnnouncement(ctxt, invalidNodeAnnReq)
|
||||||
require.Error(t.t, err, "requests without modifiers should field")
|
require.Error(t.t, err, "requests without modifiers should field")
|
||||||
|
|
||||||
|
// Alias too long.
|
||||||
|
invalidNodeAnnReq = &peersrpc.NodeAnnouncementUpdateRequest{
|
||||||
|
Alias: strings.Repeat("a", 50),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dave.UpdateNodeAnnouncement(ctxt, invalidNodeAnnReq)
|
||||||
|
require.Error(t.t, err, "failed to validate an invalid alias for an "+
|
||||||
|
"update node announcement request")
|
||||||
|
|
||||||
|
// Update Node.
|
||||||
|
newAlias := "new-alias"
|
||||||
|
|
||||||
|
nodeAnnReq := &peersrpc.NodeAnnouncementUpdateRequest{
|
||||||
|
Alias: newAlias,
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := dave.UpdateNodeAnnouncement(ctxt, nodeAnnReq)
|
||||||
|
require.NoError(t.t, err, "unable to update dave's node announcement")
|
||||||
|
|
||||||
|
expectedOps := map[string]int{
|
||||||
|
"alias": 1,
|
||||||
|
}
|
||||||
|
assertUpdateNodeAnnouncementResponse(t, response, expectedOps)
|
||||||
|
|
||||||
|
// After updating the node we expect the update to contain
|
||||||
|
// the requested color, requested alias and the new added addresses.
|
||||||
|
newDaveNodeAnn := &lnrpc.NodeUpdate{
|
||||||
|
Alias: newAlias,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll then wait for Alice to receive dave's node announcement
|
||||||
|
// with the new values.
|
||||||
|
waitForNodeAnnUpdates(
|
||||||
|
aliceSub, dave.PubKeyStr, newDaveNodeAnn, t,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Close the channel between Bob and Dave.
|
||||||
|
closeChannelAndAssert(t, net, net.Bob, chanPoint, false)
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,14 @@ import (
|
|||||||
// lnwire.NodeAnnouncement.
|
// lnwire.NodeAnnouncement.
|
||||||
type NodeAnnModifier func(*lnwire.NodeAnnouncement)
|
type NodeAnnModifier func(*lnwire.NodeAnnouncement)
|
||||||
|
|
||||||
|
// NodeAnnSetAlias is a functional option that sets the alias of the
|
||||||
|
// given node announcment.
|
||||||
|
func NodeAnnSetAlias(alias lnwire.NodeAlias) func(*lnwire.NodeAnnouncement) {
|
||||||
|
return func(nodeAnn *lnwire.NodeAnnouncement) {
|
||||||
|
nodeAnn.Alias = alias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NodeAnnSetAddrs is a functional option that allows updating the addresses of
|
// NodeAnnSetAddrs is a functional option that allows updating the addresses of
|
||||||
// the given node announcement.
|
// the given node announcement.
|
||||||
func NodeAnnSetAddrs(addrs []net.Addr) func(*lnwire.NodeAnnouncement) {
|
func NodeAnnSetAddrs(addrs []net.Addr) func(*lnwire.NodeAnnouncement) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user