Skip to content

Conversation

GeorgeTsagk
Copy link
Member

@GeorgeTsagk GeorgeTsagk commented Aug 19, 2025

Description

Adds the necessary subsystem to handle custom feature bit negotiation for tap channels. This allows us to introduce new channel features that would otherwise break backwards compatibility. We piggy-back on the existing LND messages (init & reestablish) to nest the tlv.Blob that encodes the CustomChannelType (uint64) type.

The set of active features over a channel is the intersection of the locally supported features and the features that the peer provided.

Currently we follow a "global" approach on the feature bits that we support. We don't make any distinctions between peers or channels. The locally supported feature bits is a static set.

We also don't allow reading/writing feature bits per channel, but per peer. For now the funding outpoint / funding blob arguments are ignored. When we establish a feature-set with a peer, that applies to all of our channels with that peer.

An older tapd node (i.e a node that does not contain the contents of this PR) will be treated as if they provided an empty feature set (uint64 with 0's)

Dependencies

LND lightningnetwork/lnd#10182
Lndclient lightninglabs/lndclient#239
LiT itest: lightninglabs/lightning-terminal#1138

@GeorgeTsagk GeorgeTsagk self-assigned this Aug 19, 2025
@levmi levmi moved this from 🆕 New to 🏗 In progress in Taproot-Assets Project Board Aug 21, 2025
@GeorgeTsagk GeorgeTsagk force-pushed the feature-bits branch 2 times, most recently from eb267a6 to 77f9420 Compare August 28, 2025 13:02
@GeorgeTsagk GeorgeTsagk marked this pull request as ready for review August 28, 2025 13:04
@coveralls
Copy link

coveralls commented Aug 28, 2025

Pull Request Test Coverage Report for Build 17639932889

Details

  • 55 of 181 (30.39%) changed or added relevant lines in 7 files are covered.
  • 65 unchanged lines in 14 files lost coverage.
  • Overall coverage decreased (-0.06%) to 56.912%

Changes Missing Coverage Covered Lines Changed/Added Lines %
tapchannel/aux_traffic_shaper.go 0 5 0.0%
tapfeatures/aux_feature_bits.go 8 14 57.14%
server.go 0 46 0.0%
tapfeatures/aux_channel_negotiator.go 21 90 23.33%
Files with Coverage Reduction New Missed Lines %
asset/group_key.go 2 72.15%
fn/iter.go 2 62.07%
tapchannel/aux_traffic_shaper.go 2 6.03%
tapdb/mssmt.go 2 90.45%
itest/multisig.go 3 97.94%
authmailbox/receive_subscription.go 4 77.89%
tapdb/universe.go 4 79.63%
tapchannel/aux_leaf_signer.go 5 43.18%
tapdb/assets_common.go 5 78.34%
universe/archive.go 5 79.34%
Totals Coverage Status
Change from base Build 17628726079: -0.06%
Covered Lines: 63337
Relevant Lines: 111289

💛 - Coveralls

Copy link
Member

@jtobin jtobin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few initial questions and comments, mostly about the AuxChanNegotiator handling in the RFQ system.

Copy link
Member

@jtobin jtobin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made another pass, with some additional questions and suggestions. I think everything on my end should be resolved after this.

Copy link
Member

@jtobin jtobin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 👍

}

// ourFeatures returns a slice containing all of the locally supported features.
func ourFeatures() []lnwire.FeatureBit {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a constant instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in a const array? Not aware of how we do this in the codebase

If you mean just var ourFeatures[...]lnwire.FeatureBit{a, b, c, d} I wanted to avoid that since many different goroutines may be accessing it. The current approach with the func returns a new slice so each caller gets their own pointer

// custom feature bits to include in the init message TLVs. The implementation
// can decide which features to advertise based on the peer's identity.
func (n *AuxChannelNegotiator) GetInitFeatures(
_ route.Vertex) (tlv.Blob, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think w/ the latest direction, this can now just return the feature vector directly, to be merged by lnd.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wdym? To merge this feature vector with the one that LND uses in lnwire.Init?

Might be a nice convenience since that message already uses a feature vec, but can't see the opportunities. We'd skip a few lines (just for lnwire.Init) which encode/decode the aux features within ExtraData, which is a bit more lean, but then again for the other messages we'd have to maintain the current approach as they don't have a feature-vec field.

// to drop the connection (by returning an error right here).
err = checkRequiredBits(getLocalFeatureVec(), peerVec)
if err != nil {
return err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lnd doesn't need to handle this error right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we expect LND to fail the peer connection, preventing any channels from becoming active

@github-project-automation github-project-automation bot moved this from 🏗 In progress to 👀 In review in Taproot-Assets Project Board Sep 9, 2025
@GeorgeTsagk
Copy link
Member Author

Also guarded the new hooks with the s.waitForReady call to make sure that the subsystems have been initialized, as we're using AuxChanNegotiator in the new hooks

@lightninglabs-deploy
Copy link

@Roasbeef: review reminder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 👀 In review
Development

Successfully merging this pull request may close these issues.

5 participants