-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lnrpc: Add UpdateNodeAnnouncement endpoint #5587
lnrpc: Add UpdateNodeAnnouncement endpoint #5587
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, should I add release notes to 0.13.x
or to 0.14.x
?
lnrpc/lightning.proto
Outdated
@@ -3711,6 +3718,22 @@ message ListPermissionsResponse { | |||
map<string, MacaroonPermissionList> method_permissions = 1; | |||
} | |||
|
|||
message NodeAnnouncementUpdateRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
features
and addresses
have the problem that they are sets. I do not have the full context about what kind of features are out there but we need to decided if the request will directly substitute the current features with the ones in the request or if we need a mechanism to perform join/add/subtract of single features
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to decided if the request will directly substitute the current features with the ones in the request or if we need a mechanism to perform join/add/subtract of single features
Yeah this is what I was hinting at re knowing which fields are actually being updated. Seems we could try to handle the two (?) cases explicitly. So in one mode, it's a wholesale replacement of w/e feature bits we already have advertised. In the other case, a user can specify that it wants a particular bit to be added or removed.
One possible way to do this would be to have something like an "action" defined for each entry, so something like:
enum FeatureBitAction {
ADD = 0;
REMOVE = 1;
}
map<FeatureBit, FeatureBitActiion> FeatureBitUpdate = 1;
This way we don't force the caller to fully specify all the existing feature bits, instead they say if they want a bit to be removed or added.
lnrpc/lightning.proto
Outdated
string alias = 3; | ||
|
||
// Addresses is a slice of all the node's known addresses. | ||
repeated NodeAddress addresses = 4; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar problem that the one with features
. Should we simply substitute the current node addresses with the ones that are provided in the request or we need to keep the ones in the conf file for example.
Also, should we use the default port for those addresses that are only the IP, or we should not support not providing it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the same "action" scheme I outlined above could work here, so turning it into a map of actions.
lnrpc/lightning.proto
Outdated
// Addresses is a slice of all the node's known addresses. | ||
repeated NodeAddress addresses = 4; | ||
} | ||
message NodeAnnouncementUpdateResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it is worth to return all the data that will be broadcasted to other nodes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be useful to just send what was actually updated? So like if you try to add a new address, but it's already advertised, then you get back an empty response telling you it was effectively a noop.
Related to this response handling, is that we likely want to return a gRPC status/error code, to indicate if a user tries to do something like a set a feature bit that we actually don't understand. On the other-hand, we could allow such behavior as it may be useful when paired with something like: #5346
t.Fatalf("faild to validate an invalid alias for an update node announcement request: %v", err) | ||
} | ||
|
||
// TODO(positiveblue): Add checks for features and addresses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is still not validation for these two parameters in the server implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So for feature here, we'll need to make a decision (for the validation logic), if we want to allow them to advertise feature bits unknown to us or not.
For addresses, as is we rely on net ResolveTCPAddr
(or the onion counter part) to make sure they're actually a valid address.
41decb4
to
6aa0dc4
Compare
0.14.1! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solid first time contribution! Did an initial pass over the diff, and I think the main thing that needs to be sorted out is how we handle partial updates to the set of advertised feature bits and/or addresses. See my comments inline for some suggestions.
lnrpc/lightning.proto
Outdated
@@ -3711,6 +3718,22 @@ message ListPermissionsResponse { | |||
map<string, MacaroonPermissionList> method_permissions = 1; | |||
} | |||
|
|||
message NodeAnnouncementUpdateRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to decided if the request will directly substitute the current features with the ones in the request or if we need a mechanism to perform join/add/subtract of single features
Yeah this is what I was hinting at re knowing which fields are actually being updated. Seems we could try to handle the two (?) cases explicitly. So in one mode, it's a wholesale replacement of w/e feature bits we already have advertised. In the other case, a user can specify that it wants a particular bit to be added or removed.
One possible way to do this would be to have something like an "action" defined for each entry, so something like:
enum FeatureBitAction {
ADD = 0;
REMOVE = 1;
}
map<FeatureBit, FeatureBitActiion> FeatureBitUpdate = 1;
This way we don't force the caller to fully specify all the existing feature bits, instead they say if they want a bit to be removed or added.
lnrpc/lightning.proto
Outdated
string alias = 3; | ||
|
||
// Addresses is a slice of all the node's known addresses. | ||
repeated NodeAddress addresses = 4; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the same "action" scheme I outlined above could work here, so turning it into a map of actions.
lnrpc/lightning.proto
Outdated
// Addresses is a slice of all the node's known addresses. | ||
repeated NodeAddress addresses = 4; | ||
} | ||
message NodeAnnouncementUpdateResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be useful to just send what was actually updated? So like if you try to add a new address, but it's already advertised, then you get back an empty response telling you it was effectively a noop.
Related to this response handling, is that we likely want to return a gRPC status/error code, to indicate if a user tries to do something like a set a feature bit that we actually don't understand. On the other-hand, we could allow such behavior as it may be useful when paired with something like: #5346
t.Fatalf("faild to validate an invalid alias for an update node announcement request: %v", err) | ||
} | ||
|
||
// TODO(positiveblue): Add checks for features and addresses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So for feature here, we'll need to make a decision (for the validation logic), if we want to allow them to advertise feature bits unknown to us or not.
For addresses, as is we rely on net ResolveTCPAddr
(or the onion counter part) to make sure they're actually a valid address.
Thank you so much for the feedback @Roasbeef I think it is enough for the next iteration, I will ping you after applying the changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gave this PR a quick first-pass review, mostly to answer some of your questions.
Nice work so far, definitely looks like you're on the right track. Looking forward to the next iteration.
6aa0dc4
to
cf1e095
Compare
cf1e095
to
fca3156
Compare
rpcserver.go
Outdated
ops := &lnrpc.Op{Entity: "features"} | ||
|
||
fsets := make(map[feature.Set]*lnwire.RawFeatureVector) | ||
sets := []feature.Set{feature.SetNodeAnn} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Roasbeef should the endpoint allow the user to update ANY feature set? (I think yes... but I am not sure)
In that case, we should include it in the proto request (set-bit-action)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think any feature, other than features we have set by default (existing in the feature deps set).
rpcserver.go
Outdated
// Ensure that all of our feature sets properly set any | ||
// dependent features. | ||
fv := lnwire.NewFeatureVector(raw, lnwire.Features) | ||
err := feature.ValidateDeps(fv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to validate anything else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above comment, this ensures the features are well defined, but can possibly allow a user to over write a feature we set (like anchor channels), which we want to prevent IMO.
rpcserver.go
Outdated
removeAddr := make([]net.Addr, 0, len(updates)) | ||
addAddr := make([]net.Addr, 0, len(updates)) | ||
for _, update := range updates { | ||
addr, err := net.ResolveTCPAddr(update.Address.GetNetwork(), update.Address.GetAddr()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How should I make this work with tor? Should I instead use parseAddr using the node configuration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, using parseAddr
will ensure that if Tor is active, the DNS request is tunneled over that.
rpcserver.go
Outdated
LastUpdate: time.Unix(int64(newNodeAnn.Timestamp), 0), | ||
Addresses: newNodeAnn.Addresses, | ||
Alias: newNodeAnn.Alias.String(), | ||
Features: lnwire.NewFeatureVector( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is what causes me a bit of discomfort, the endpoint will broadcast the node announcement changes but it can also be used for updating other feature sets?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean other feature sets? You mean things that we don't actually understand?
rpcserver.go
Outdated
} | ||
|
||
if len(nodeModifiers) == 0 { | ||
return nil, fmt.Errorf("unable detect any new values to update " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When only updating features, UpdateNodeAnnouncement returns an error (but still updates the featurebit) .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for noticing @sputn1ck
Actually this can be tricky because even if when we have updated some parts of the node it is not until the end of the function that we update the on-disk version of our announcement so other sub-systems don't become out of sync + announce those changes to our peers.
I will return resp
instead of nil
so the user always have track of what operations were performed. Even so, if some operations succeed but the endpoint fails before completing the full flow the user will have to call it again until it succeeds to ensure that the copy on disk + our peers have the correct node announcement version
13d3537
to
2b4bafb
Compare
c334ca8
to
fd32aa8
Compare
New endpoint for the `Peers` subrpc.
fd32aa8
to
2ada770
Compare
@Roasbeef I added the new command for What new uses for the sub-server do you have in mind 👀? |
Basic logic for the endpoint: - Get the current nodeAnn information - Calculate modifications - Apply modifications - Return changes
8c9f798
to
78a1a93
Compare
78a1a93
to
fdfdd10
Compare
@Roasbeef: review reminder |
See this comment: #6262 (comment). More generically, this sub-server lets us move towards an architectures where a main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🌾
@positiveblue I noticed that changing an alias using |
As is yeah, and imo that's the correct behavior, as arguably a user shouldn't set the config level param if they want to have it be updated dynamically. There also isn't a great way to distinguish between a particular field of the node announcement that should ignore the static config values. |
If you don't set the config level parameters, the dynamically set alias is still forgotten after a restart. The node will revert to a truncated pubkey as the alias. How can one use this api in a way that no default alias or other node announcement fields can leak during restarts? |
Ah yeah I think that's an oversight, we should correct that. The gap here is that we didn't add a test case for node restart. |
Allow users to change nodeAnnouncement values such Color, Alias, Features or
Addresses and broadcast the update to its peers without having to
restart the node.
Fixes #5466