lnrpc/peers: handle feature bit changes in updateNodeAnnouncement

This commit is contained in:
positiveblue 2022-01-02 15:56:04 -08:00
parent 76196db70e
commit ae2aa5671f
No known key found for this signature in database
GPG key ID: 4FFF2510928804DC
5 changed files with 171 additions and 1 deletions

View file

@ -141,6 +141,11 @@ func (m *Manager) GetRaw(set Set) *lnwire.RawFeatureVector {
return lnwire.NewRawFeatureVector() return lnwire.NewRawFeatureVector()
} }
// SetRaw sets a new raw feature vector for the given set.
func (m *Manager) SetRaw(set Set, raw *lnwire.RawFeatureVector) {
m.fsets[set] = raw
}
// Get returns a feature vector for the passed set. If no set is known, an empty // Get returns a feature vector for the passed set. If no set is known, an empty
// feature vector is returned. // feature vector is returned.
func (m *Manager) Get(set Set) *lnwire.FeatureVector { func (m *Manager) Get(set Set) *lnwire.FeatureVector {

View file

@ -10,6 +10,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@ -241,6 +242,68 @@ func (s *Server) updateAddresses(currentAddresses []net.Addr,
return newAddrs, ops, nil return newAddrs, ops, nil
} }
// updateFeatures computes the new raw SetNodeAnn after executing the update
// actions.
func (s *Server) updateFeatures(currentfeatures *lnwire.RawFeatureVector,
updates []*UpdateFeatureAction) (*lnwire.RawFeatureVector,
*lnrpc.Op, error) {
ops := &lnrpc.Op{Entity: "features"}
raw := currentfeatures.Clone()
for _, update := range updates {
bit := lnwire.FeatureBit(update.FeatureBit)
switch update.Action {
case UpdateAction_ADD:
if raw.IsSet(bit) {
return nil, nil, fmt.Errorf(
"invalid add action for bit %v, "+
"bit is already set",
update.FeatureBit,
)
}
raw.Set(bit)
ops.Actions = append(
ops.Actions,
fmt.Sprintf("%s set", lnwire.Features[bit]),
)
case UpdateAction_REMOVE:
if !raw.IsSet(bit) {
return nil, nil, fmt.Errorf(
"invalid remove action for bit %v, "+
"bit is already unset",
update.FeatureBit,
)
}
raw.Unset(bit)
ops.Actions = append(
ops.Actions,
fmt.Sprintf("%s unset", lnwire.Features[bit]),
)
default:
return nil, nil, fmt.Errorf(
"invalid update action (%v) for bit %v",
update.Action,
update.FeatureBit,
)
}
}
// Validate our new SetNodeAnn.
fv := lnwire.NewFeatureVector(raw, lnwire.Features)
if err := feature.ValidateDeps(fv); err != nil {
return nil, nil, fmt.Errorf(
"invalid feature set (SetNodeAnn): %v",
err,
)
}
return raw, ops, nil
}
// UpdateNodeAnnouncement allows the caller to update the node parameters // UpdateNodeAnnouncement allows the caller to update the node parameters
// and broadcasts a new version of the node announcement to its peers. // and broadcasts a new version of the node announcement to its peers.
func (s *Server) UpdateNodeAnnouncement(_ context.Context, func (s *Server) UpdateNodeAnnouncement(_ context.Context,
@ -256,7 +319,21 @@ func (s *Server) UpdateNodeAnnouncement(_ context.Context,
"announcement: %v", err) "announcement: %v", err)
} }
// TODO(positiveblue): apply feature bit modifications if len(req.FeatureUpdates) > 0 {
features, ops, err := s.updateFeatures(
currentNodeAnn.Features,
req.FeatureUpdates,
)
if err != nil {
return nil, fmt.Errorf("error trying to update node "+
"features: %w", err)
}
resp.Ops = append(resp.Ops, ops)
nodeModifiers = append(
nodeModifiers,
netann.NodeAnnSetFeatures(features),
)
}
if req.Color != "" { if req.Color != "" {
color, err := lncfg.ParseHexColor(req.Color) color, err := lncfg.ParseHexColor(req.Color)

View file

@ -841,6 +841,15 @@ func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
) )
} }
// This feature bit is used to test that our endpoint sets/unsets
// feature bits properly. If the current FeatureBit is set by default
// update this one for another one unset by default at random.
featureBit := lnrpc.FeatureBit_WUMBO_CHANNELS_REQ
featureIdx := uint32(featureBit)
if _, ok := resp.Features[featureIdx]; ok {
t.Fatalf("unexpected feature bit enabled by default")
}
defaultDaveNodeAnn := &lnrpc.NodeUpdate{ defaultDaveNodeAnn := &lnrpc.NodeUpdate{
Alias: resp.Alias, Alias: resp.Alias,
Color: resp.Color, Color: resp.Color,
@ -912,16 +921,25 @@ func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
}, },
} }
updateFeatureActions := []*peersrpc.UpdateFeatureAction{
{
Action: peersrpc.UpdateAction_ADD,
FeatureBit: featureBit,
},
}
nodeAnnReq := &peersrpc.NodeAnnouncementUpdateRequest{ nodeAnnReq := &peersrpc.NodeAnnouncementUpdateRequest{
Alias: newAlias, Alias: newAlias,
Color: newColor, Color: newColor,
AddressUpdates: updateAddressActions, AddressUpdates: updateAddressActions,
FeatureUpdates: updateFeatureActions,
} }
response, err := dave.UpdateNodeAnnouncement(ctxt, nodeAnnReq) response, err := dave.UpdateNodeAnnouncement(ctxt, nodeAnnReq)
require.NoError(t.t, err, "unable to update dave's node announcement") require.NoError(t.t, err, "unable to update dave's node announcement")
expectedOps := map[string]int{ expectedOps := map[string]int{
"features": 1,
"color": 1, "color": 1,
"alias": 1, "alias": 1,
"addresses": 3, "addresses": 3,
@ -951,6 +969,63 @@ func testUpdateNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
aliceSub, dave.PubKeyStr, newDaveNodeAnn, t, aliceSub, dave.PubKeyStr, newDaveNodeAnn, t,
) )
// Check that the feature bit was set correctly.
resp, err = dave.GetInfo(ctxt, nodeInfoReq)
require.NoError(t.t, err, "unable to get dave's information")
if _, ok := resp.Features[featureIdx]; !ok {
t.Fatalf("failed to set feature bit")
}
// Check that we cannot set a feature bit that is already set.
nodeAnnReq = &peersrpc.NodeAnnouncementUpdateRequest{
FeatureUpdates: updateFeatureActions,
}
_, err = dave.UpdateNodeAnnouncement(ctxt, nodeAnnReq)
require.Error(
t.t, err, "missing expected error: cannot set a feature bit "+
"that is already set",
)
// Check that we can unset feature bits.
updateFeatureActions = []*peersrpc.UpdateFeatureAction{
{
Action: peersrpc.UpdateAction_REMOVE,
FeatureBit: featureBit,
},
}
nodeAnnReq = &peersrpc.NodeAnnouncementUpdateRequest{
FeatureUpdates: updateFeatureActions,
}
response, err = dave.UpdateNodeAnnouncement(ctxt, nodeAnnReq)
require.NoError(t.t, err, "unable to update dave's node announcement")
expectedOps = map[string]int{
"features": 1,
}
assertUpdateNodeAnnouncementResponse(t, response, expectedOps)
resp, err = dave.GetInfo(ctxt, nodeInfoReq)
require.NoError(t.t, err, "unable to get dave's information")
if _, ok := resp.Features[featureIdx]; ok {
t.Fatalf("failed to unset feature bit")
}
// Check that we cannot unset a feature bit that is already unset.
nodeAnnReq = &peersrpc.NodeAnnouncementUpdateRequest{
FeatureUpdates: updateFeatureActions,
}
_, err = dave.UpdateNodeAnnouncement(ctxt, nodeAnnReq)
require.Error(
t.t, err, "missing expected error: cannot unset a feature bit "+
"that is already unset",
)
// Close the channel between Bob and Dave. // Close the channel between Bob and Dave.
closeChannelAndAssert(t, net, net.Bob, chanPoint, false) closeChannelAndAssert(t, net, net.Bob, chanPoint, false)
} }

View file

@ -38,6 +38,14 @@ func NodeAnnSetColor(newColor color.RGBA) func(*lnwire.NodeAnnouncement) {
} }
} }
// NodeAnnSetFeatures is a functional option that allows updating the features of
// the given node announcement.
func NodeAnnSetFeatures(features *lnwire.RawFeatureVector) func(*lnwire.NodeAnnouncement) {
return func(nodeAnn *lnwire.NodeAnnouncement) {
nodeAnn.Features = features
}
}
// NodeAnnSetTimestamp is a functional option that sets the timestamp of the // NodeAnnSetTimestamp is a functional option that sets the timestamp of the
// announcement to the current time, or increments it if the timestamp is // announcement to the current time, or increments it if the timestamp is
// already in the future. // already in the future.

View file

@ -2771,6 +2771,11 @@ func (s *server) updateAndBrodcastSelfNode(
return fmt.Errorf("can't set self node: %v", err) return fmt.Errorf("can't set self node: %v", err)
} }
// Update the feature bits for the SetNodeAnn in case they changed.
s.featureMgr.SetRaw(
feature.SetNodeAnn, selfNode.Features.RawFeatureVector,
)
// Finally, propagate it to the nodes in the network. // Finally, propagate it to the nodes in the network.
err = s.BroadcastMessage(nil, &newNodeAnn) err = s.BroadcastMessage(nil, &newNodeAnn)
if err != nil { if err != nil {