-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Aux feature bits #10182
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
Aux feature bits #10182
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.
Summary of Changes
Hello @GeorgeTsagk, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces a new AuxChannelNegotiator component to LND, enabling auxiliary channel implementations to dynamically inject and process custom feature bits during peer initialization (init) and channel reestablishment (channel_reestablish) messages. These custom feature bits are transmitted as TLV (Type-Length-Value) blobs, ensuring backward compatibility as nodes not supporting them will simply ignore the unknown TLV. This enhancement provides a flexible mechanism for extending channel behavior based on negotiated features.
Highlights
- New AuxChannelNegotiator Interface: Introduced an interface (lnwallet.AuxChannelNegotiator) that defines methods for getting and processing custom feature bits during init and channel_reestablish messages, allowing for dynamic channel behavior.
- TLV-Encoded Auxiliary Features: Custom feature bits are now transmitted as tlv.Blob (aliased as lnwire.AuxFeatureBits) within their own TLV type (AuxFeatureBitsTLV), ensuring extensibility and backward compatibility.
- Integration into Messaging Flow: The AuxChannelNegotiator is integrated into the htlcswitch and peer components to send and receive these auxiliary feature bits during the init and channel_reestablish message exchanges.
- Configurability: The new negotiator is exposed through AuxComponents in config_builder.go and peer.Config, allowing for its optional configuration and use within the LND system.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
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.
Code Review
This pull request introduces an AuxChannelNegotiator
component to facilitate custom feature bit negotiation during channel initialization and re-establishment. The changes are well-integrated across the relevant parts of the codebase, including configuration, peer management, and the htlcswitch. The new interfaces and message modifications appear correct and align with the described functionality.
I've identified a potential issue with error handling in htlcswitch/link.go
where an error from the negotiator might be silently ignored. Additionally, there are some minor opportunities to improve log message formatting for better readability and consistency with the provided style guide. Overall, this is a solid addition.
48f9e78
to
e24e285
Compare
I extended the Realized that |
lnwire/channel_reestablish.go
Outdated
// for custom channel negotiation. This is used by aux channel | ||
// implementations to negotiate custom channel behavior during | ||
// channel reestablishment. | ||
AuxFeatures fn.Option[AuxFeatureBits] |
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 don't think we need to manifest this here. It can just be a part of the ExtraData
below, and have client be able to read/write 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.
Alright after looking at the lifecycle of the lnwire.Init
/ lnwire.ChannelReestablish
wire messages here is my summary:
Seems like our convention is that the fields of the wire messages (regardless of where they end up being encoded) are unfolded on the struct level. Then when we dispatch the message via cfg.Peer.SendMessage
everything will be encoded into the appropriate record, with ExtraData
hosting most of the misc/optional fields.
If we switch the approach to instead use ExtraData
everywhere in the hooks:
- By setting
ExtraData
prematurely (before the wire message is encoded/sent) then we'll end up having the data overwritten by theEncode
method of that message. We could change the way we encode records intoExtraData
for the desired wire messages (some flag that maintains existing records?), but would change code that is used by all wire messages. - Within the
ExtraData
namespace we still have to guard against record type conflict. We're currently able to do that becauseAuxFeatures
is defined on the lnd wire message itself, alongside the rest of the fields that get encoded intoExtraData
-- making it easier to avoid TLV conflicts.
We can somehow leverage the existing lnwire.MergeAndEncode, but that still requires for a field to be declared for the init/reestablish messages, like we've done elsewhere:
Lines 40 to 44 in e24e285
// CustomRecords maps TLV types to byte slices, storing arbitrary data | |
// intended for inclusion in the ExtraData field of the Shutdown | |
// message. | |
CustomRecords CustomRecords |
The approach above seems to be more generic but might be too big of a placeholder for this scope -- we know we want to encode just a single record for the features here.
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.
Agree with @Roasbeef here - we should remove the AuxFeatureBitsTLV
and only pass custom records between lnd
and tapd
. AuxFeatureBitsTLV
is only meaningful to tapd
, but defining and managing it in lnd
, it deeply couples the two - whenever a new feature bit tlv is added in tapd
, lnd
is now forced to make updates.
The existence of the CustomRecords
mechanism (TLVType >= 65536) provides a much cleaner path that avoids the problems.
Line 163 in b34fc96
func ParseAndExtractCustomRecords(allExtraData ExtraOpaqueData, |
-
No New TLV Type in
lnd
: We should remove the definition ofAuxFeatureBitsTLV
from lnd. lnd should not have a hardcoded TLV type that is specific to an auxiliary service. -
tapd
Defines Its Own Types: tapd should define its own TLV types within the custom record range (>= 65536). For example, tapd could defineTapdInitDataTLV = 65536
andTapdReestablishDataTLV = 65537
. -
lnd
ParsesCustomRecords
: lnd's wire parsing logic for theinit
andchannel_reestablish
messages should be modified to useParseAndExtractCustomRecords
. It would parse out any known, lnd-specific TLV records, and then bundle all remaining records in the custom range into aCustomRecords
map. -
The Interface Passes
CustomRecords
: TheAuxChannelNegotiator
interface would be changed to pass thisCustomRecords
map instead of a specifictlv.Blob
.
e24e285
to
ba1124b
Compare
Just wanted to mention that the above:
is not true. In the previous version we exposed the tlv type that would be used for the purpose of hosting aux feature bits, and the only thing that LND needed to be aware of was the key under which that blob would be placed. The contents of the blob (the actual aux feature bit vector) is managed and encoded/decoded by tapd. We wouldn't need to unfold its contents or give LND any further awareness as to what it represents, and also we could extend it solely in tapd without needing to update LND. What we would need to update LND for is the scenario where we need to introduce a new, different custom record to host a different blob. Latest push removes the AuxFeatures TLV related code and only allows injecting PTAL @Roasbeef @yyforyongyu |
9efe3bd
to
8c80f46
Compare
lnwire/init_message.go
Outdated
msg.CustomRecords = customRecords | ||
} | ||
|
||
if len(extraData) > 0 { |
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.
the if statement here and above is just to avoid populating the field with a nil value, which would lead to misallignments in the unit test assertions for the wire message
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 don't think that's needed, also the test is not updated. This method is also used in DynCommit
and we need to update it similarly to this line,
Line 1050 in 82f77e5
msg.ExtraData = RandExtraOpaqueData(t, ignoreRecords) |
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.
Cool this version is much lighter and cleaner! I think we need to add a unit test to validate whether the new Decode
method works as expected. Examples can be found here,
lnd/lnwire/channel_update_2_test.go
Lines 11 to 13 in 82f77e5
// TestChanUpdate2EncodeDecode tests the encoding and decoding of the | |
// ChannelUpdate2 message using hardcoded byte slices. | |
func TestChanUpdate2EncodeDecode(t *testing.T) { |
or here,
lnd/lnwire/dyn_propose_test.go
Lines 10 to 12 in 82f77e5
// TestDynProposeEncodeDecode checks that the Encode and Decode methods work as | |
// expected. | |
func TestDynProposeEncodeDecode(t *testing.T) { |
lnwire/init_message.go
Outdated
msg.CustomRecords = customRecords | ||
} | ||
|
||
if len(extraData) > 0 { |
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 don't think that's needed, also the test is not updated. This method is also used in DynCommit
and we need to update it similarly to this line,
Line 1050 in 82f77e5
msg.ExtraData = RandExtraOpaqueData(t, ignoreRecords) |
lnwire/init_message.go
Outdated
} | ||
|
||
if len(extraData) > 0 { | ||
msg.ExtraData = extraData |
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 means the msg.ExtraData
will always have the raw custom data, when the data read from the wire only contains custom records. I think we should add tests here, similar to https://github.com/lightningnetwork/lnd/blob/master/lnwire/dyn_commit_test.go or https://github.com/lightningnetwork/lnd/blob/master/lnwire/channel_update_2_test.go
There's also #10140 that can be used as example.
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.
Added a new test in lnwire/init_message_test.go
Also included the msg.ExtraData = RandExtraOpaqueData(t, ignoreRecords)
in the existing random test data generator.
8c80f46
to
ef509a0
Compare
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.
Looking good - only a comment about the unit test!
We introduce this new interface with the purpose of injecting and handling custom records on the init message, and also notifying external components when receiving the ChannelReady or ChannelReestablish message.
We now plug-in the aux channel negotiator to the server impl config. We also provide it to the peer config as that's where it's needed in order to inject custom records in the appropriate peer messages.
Before calling the new interface we first add the ability for the peer message itself to encode the new data records.
This is the final step, we actually call the interface and either provide or retrieve the custom features over the message. We also notify the aux components when channel reestablish is received.
In order to help external components to query the custom records of a channel we need to expose the remote peer pub key. We could look-up custom records based on the funding outpoint, but that relation is established when receiving the ChannelReady message. The external components may query the AuxChanState before that message is received, so let's make sure the peer pub key is also available.
We notify the aux channel negotiator that an established channel is now ready to use.
ef509a0
to
2302deb
Compare
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🏁
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 ❄️
Description
Adds a new aux component named
AuxChannelNegotiator
. The responsibility of this component is to inject custom feature bits on the peer init & reestablish messages. The interface allows for both reading and setting any custom feature bits.The aux feature bits are treated as a
tlv.Blob
by LND, and reside within their own TLV type. So any node that does not support/understand aux feature bits will simply drop the TLV and not read it.