refactor+multi: use *lnwire.FeatureVector for ChannelEdgeInfo features

In this commit, we move the serialisation details of a channel's
features to the DB layer and change the `models` field to instead use a
more useful `*lnwire.FeatureVector` type.

This makes the features easier to work with and moves the serialisation
to where it is actually used.
This commit is contained in:
Elle Mouton committed 2025-07-01 17:02:07 +02:00
1 parent d8a12a5e57
commit 2f2845dfc0
14 files changed
+70 -78

No files matched your search

+7 -16
View File
@@ -416,6 +416,7 @@ func TestEdgeInsertionDeletion(t *testing.T) {
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: outpoint,
Capacity: 9000,
}
@@ -479,12 +480,6 @@ func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32,
Index: outPointIndex,
}
var (
features = lnwire.NewRawFeatureVector()
featureBuf bytes.Buffer
)
_ = features.Encode(&featureBuf)
node1Pub, _ := node1.PubKey()
node2Pub, _ := node2.PubKey()
edgeInfo := models.ChannelEdgeInfo{
@@ -499,7 +494,7 @@ func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32,
ChannelPoint: outpoint,
Capacity: 9000,
ExtraOpaqueData: make([]byte, 0),
Features: featureBuf.Bytes(),
Features: lnwire.EmptyFeatureVector(),
}
copy(edgeInfo.NodeKey1Bytes[:], node1Pub.SerializeCompressed())
@@ -663,8 +658,8 @@ func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo,
t.Fatalf("bitcoinkey2 doesn't match")
}
if !bytes.Equal(e1.Features, e2.Features) {
t.Fatalf("features doesn't match: %x vs %x", e1.Features,
if !e1.Features.Equals(e2.Features.RawFeatureVector) {
t.Fatalf("features don't match: %v vs %v", e1.Features,
e2.Features)
}
@@ -741,12 +736,6 @@ func createChannelEdge(node1, node2 *models.LightningNode,
Index: prand.Uint32(),
}
var (
features = lnwire.NewRawFeatureVector()
featureBuf bytes.Buffer
)
_ = features.Encode(&featureBuf)
// Add the new edge to the database, this should proceed without any
// errors.
edgeInfo := &models.ChannelEdgeInfo{
@@ -759,7 +748,7 @@ func createChannelEdge(node1, node2 *models.LightningNode,
2, 2, 2, 2,
3, 3, 3, 3, 3,
},
Features: featureBuf.Bytes(),
Features: lnwire.EmptyFeatureVector(),
}
copy(edgeInfo.NodeKey1Bytes[:], firstNode[:])
copy(edgeInfo.NodeKey2Bytes[:], secondNode[:])
@@ -1617,6 +1606,7 @@ func fillTestGraph(t testing.TB, graph *ChannelGraph, numNodes,
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: op,
Capacity: 1000,
}
@@ -1799,6 +1789,7 @@ func TestGraphPruning(t *testing.T) {
BitcoinSig1Bytes: testSig.Serialize(),
BitcoinSig2Bytes: testSig.Serialize(),
},
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: op,
Capacity: 1000,
}
+15 -2
View File
@@ -4291,7 +4291,12 @@ func putChanEdgeInfo(edgeIndex kvdb.RwBucket,
return err
}
if err := wire.WriteVarBytes(&b, 0, edgeInfo.Features); err != nil {
var featureBuf bytes.Buffer
if err := edgeInfo.Features.Encode(&featureBuf); err != nil {
return fmt.Errorf("unable to encode features: %w", err)
}
if err := wire.WriteVarBytes(&b, 0, featureBuf.Bytes()); err != nil {
return err
}
@@ -4374,11 +4379,19 @@ func deserializeChanEdgeInfo(r io.Reader) (models.ChannelEdgeInfo, error) {
return models.ChannelEdgeInfo{}, err
}
edgeInfo.Features, err = wire.ReadVarBytes(r, 0, 900, "features")
featureBytes, err := wire.ReadVarBytes(r, 0, 900, "features")
if err != nil {
return models.ChannelEdgeInfo{}, err
}
features := lnwire.NewRawFeatureVector()
err = features.Decode(bytes.NewReader(featureBytes))
if err != nil {
return models.ChannelEdgeInfo{}, fmt.Errorf("unable to decode "+
"features: %w", err)
}
edgeInfo.Features = lnwire.NewFeatureVector(features, lnwire.Features)
proof := &models.ChannelAuthProof{}
proof.NodeSig1Bytes, err = wire.ReadVarBytes(r, 0, 80, "sigs")
+4 -3
View File
@@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/fn/v2"
"github.com/lightningnetwork/lnd/lnwire"
)
// ChannelEdgeInfo represents a fully authenticated channel along with all its
@@ -46,9 +47,9 @@ type ChannelEdgeInfo struct {
BitcoinKey2Bytes [33]byte
bitcoinKey2 *btcec.PublicKey
// Features is an opaque byte slice that encodes the set of channel
// specific features that this channel edge supports.
Features []byte
// Features is the list of protocol features supported by this channel
// edge.
Features *lnwire.FeatureVector
// AuthProof is the authentication proof for this channel. This proof
// contains a set of signatures binding four identities, which attests
+10 -25
View File
@@ -3833,26 +3833,16 @@ func insertChannel(ctx context.Context, db SQLQueries,
}
// Insert any channel features.
if len(edge.Features) != 0 {
chanFeatures := lnwire.NewRawFeatureVector()
err := chanFeatures.Decode(bytes.NewReader(edge.Features))
for feature := range edge.Features.Features() {
err = db.InsertChannelFeature(
ctx, sqlc.InsertChannelFeatureParams{
ChannelID: dbChanID,
FeatureBit: int32(feature),
},
)
if err != nil {
return nil, err
}
fv := lnwire.NewFeatureVector(chanFeatures, lnwire.Features)
for feature := range fv.Features() {
err = db.InsertChannelFeature(
ctx, sqlc.InsertChannelFeatureParams{
ChannelID: dbChanID,
FeatureBit: int32(feature),
},
)
if err != nil {
return nil, fmt.Errorf("unable to insert "+
"channel(%d) feature(%v): %w", dbChanID,
feature, err)
}
return nil, fmt.Errorf("unable to insert channel(%d) "+
"feature(%v): %w", dbChanID, feature, err)
}
}
@@ -3975,11 +3965,6 @@ func getAndBuildEdgeInfo(ctx context.Context, db SQLQueries,
return nil, err
}
var featureBuf bytes.Buffer
if err := fv.Encode(&featureBuf); err != nil {
return nil, fmt.Errorf("unable to encode features: %w", err)
}
recs, err := lnwire.CustomRecords(extras).Serialize()
if err != nil {
return nil, fmt.Errorf("unable to serialize extra signed "+
@@ -4002,7 +3987,7 @@ func getAndBuildEdgeInfo(ctx context.Context, db SQLQueries,
BitcoinKey2Bytes: btcKey2,
ChannelPoint: *op,
Capacity: btcutil.Amount(dbChan.Capacity.Int64),
Features: featureBuf.Bytes(),
Features: fv,
ExtraOpaqueData: recs,
}