mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 09:48:19 +01:00
lnrpc/peers: handle feature bit changes in updateNodeAnnouncement
This commit is contained in:
parent
76196db70e
commit
ae2aa5671f
5 changed files with 171 additions and 1 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue