multi: add and use V1 constructor for models.ChannelEdgeInfo

This makes it clear what fields must/can be set for a V1 channel.

Introduce NewV1Channel constructor to create v1 channel edges with
proper initialization and validation. The constructor:

- Takes required fields (chanID, chainHash, node keys) as parameters
- Takes v1-specific fields (bitcoin keys, extra opaque data) via
  ChannelV1Fields struct
- Accepts optional fields (capacity, channel point, features, proof)
  via functional options (WithCapacity, WithChannelPoint, etc.)
- Validates that if an AuthProof is provided, its version matches the
  channel version

This makes it clear which fields are required vs optional for v1
channels and prevents incorrectly initialized channel edges. All
tests and production code updated to use the constructor.
This commit is contained in:
Elle Mouton committed 2026-02-13 07:21:22 +02:00
1 parent 7a260ee103
commit ba6222b521
18 files changed
+853 -575

No files matched your search

+14 -9
View File
@@ -12,6 +12,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
graphdb "github.com/lightningnetwork/lnd/graph/db" graphdb "github.com/lightningnetwork/lnd/graph/db"
"github.com/lightningnetwork/lnd/graph/db/models" "github.com/lightningnetwork/lnd/graph/db/models"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@@ -492,16 +493,20 @@ func (d *testDBGraph) addRandChannel(node1, node2 *btcec.PublicKey,
} }
chanID := randChanID() chanID := randChanID()
edge := &models.ChannelEdgeInfo{ nodeKey1 := route.NewVertex(lnNode1)
Version: lnwire.GossipVersion1, nodeKey2 := route.NewVertex(lnNode2)
ChannelID: chanID.ToUint64(), btcKey1 := route.NewVertex(lnNode1)
Capacity: capacity, btcKey2 := route.NewVertex(lnNode2)
Features: lnwire.EmptyFeatureVector(), edge, err := models.NewV1Channel(
chanID.ToUint64(), chainhash.Hash{}, nodeKey1, nodeKey2,
&models.ChannelV1Fields{
BitcoinKey1Bytes: btcKey1,
BitcoinKey2Bytes: btcKey2,
}, models.WithCapacity(capacity),
)
if err != nil {
return nil, nil, err
} }
copy(edge.NodeKey1Bytes[:], lnNode1.SerializeCompressed())
copy(edge.NodeKey2Bytes[:], lnNode2.SerializeCompressed())
copy(edge.BitcoinKey1Bytes[:], lnNode1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], lnNode2.SerializeCompressed())
if err := d.db.AddChannelEdge(ctx, edge); err != nil { if err := d.db.AddChannelEdge(ctx, edge); err != nil {
return nil, nil, err return nil, nil, err
+20 -13
View File
@@ -2818,19 +2818,26 @@ func (d *AuthenticatedGossiper) handleChanAnnouncement(ctx context.Context,
// With the proof validated (if necessary), we can now store it within // With the proof validated (if necessary), we can now store it within
// the database for our path finding and syncing needs. // the database for our path finding and syncing needs.
edge := &models.ChannelEdgeInfo{ edge, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, scid.ToUint64(), ann.ChainHash, ann.NodeID1, ann.NodeID2,
ChannelID: scid.ToUint64(), &models.ChannelV1Fields{
ChainHash: ann.ChainHash, BitcoinKey1Bytes: ann.BitcoinKey1,
NodeKey1Bytes: ann.NodeID1, BitcoinKey2Bytes: ann.BitcoinKey2,
NodeKey2Bytes: ann.NodeID2, ExtraOpaqueData: ann.ExtraOpaqueData,
BitcoinKey1Bytes: ann.BitcoinKey1, },
BitcoinKey2Bytes: ann.BitcoinKey2, models.WithChanProof(proof), models.WithFeatures(ann.Features),
AuthProof: proof, )
Features: lnwire.NewFeatureVector( if err != nil {
ann.Features, lnwire.Features, key := newRejectCacheKey(
), ann.GossipVersion(),
ExtraOpaqueData: ann.ExtraOpaqueData, scid.ToUint64(),
sourceToPub(nMsg.source),
)
_, _ = d.recentRejects.Put(key, &cachedReject{})
log.Errorf("unable to create channel edge: %v", err)
nMsg.err <- err
return nil, false
} }
// If there were any optional message fields provided, we'll include // If there were any optional message fields provided, we'll include
+9 -5
View File
@@ -272,11 +272,15 @@ func (r *mockGraphSource) GetChannelByID(chanID lnwire.ShortChannelID) (
return nil, nil, nil, graphdb.ErrEdgeNotFound return nil, nil, nil, graphdb.ErrEdgeNotFound
} }
return &models.ChannelEdgeInfo{ zombieEdge, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, 0, chainhash.Hash{}, pubKeys[0], pubKeys[1],
NodeKey1Bytes: pubKeys[0], &models.ChannelV1Fields{},
NodeKey2Bytes: pubKeys[1], )
}, nil, nil, graphdb.ErrZombieEdge if err != nil {
return nil, nil, nil, err
}
return zombieEdge, nil, nil, graphdb.ErrZombieEdge
} }
edges := r.edges[chanID.ToUint64()] edges := r.edges[chanID.ToUint64()]
+170 -170
View File
@@ -17,10 +17,10 @@ import (
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/fn/v2"
graphdb "github.com/lightningnetwork/lnd/graph/db" graphdb "github.com/lightningnetwork/lnd/graph/db"
"github.com/lightningnetwork/lnd/graph/db/models" "github.com/lightningnetwork/lnd/graph/db/models"
"github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch"
@@ -65,18 +65,17 @@ func TestAddProof(t *testing.T) {
ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
// After utxo was recreated adding the edge without the proof. // After utxo was recreated adding the edge without the proof.
edge := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(bitcoinKey1)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(bitcoinKey2)
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes,
NodeKey2Bytes: node2.PubKeyBytes,
AuthProof: nil,
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some(script),
}
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
edge, err := models.NewV1Channel(
chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
BitcoinKey1Bytes: btcKey1,
BitcoinKey2Bytes: btcKey2,
}, models.WithFundingScript(script),
)
require.NoError(t, err)
require.NoError(t, ctx.builder.AddEdge(ctxb, edge)) require.NoError(t, ctx.builder.AddEdge(ctxb, edge))
// Now we'll attempt to update the proof and check that it has been // Now we'll attempt to update the proof and check that it has been
@@ -152,17 +151,20 @@ func TestIgnoreChannelEdgePolicyForUnknownChannel(t *testing.T) {
} }
ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
edge := &models.ChannelEdgeInfo{ pub1Vertex, err := route.NewVertexFromBytes(pub1[:])
Version: lnwire.GossipVersion1, require.NoError(t, err)
ChannelID: chanID.ToUint64(), pub2Vertex, err := route.NewVertexFromBytes(pub2[:])
NodeKey1Bytes: pub1, require.NoError(t, err)
NodeKey2Bytes: pub2,
BitcoinKey1Bytes: pub1, edge, err := models.NewV1Channel(
BitcoinKey2Bytes: pub2, chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
AuthProof: nil, pub1Vertex, pub2Vertex, &models.ChannelV1Fields{
Features: lnwire.EmptyFeatureVector(), BitcoinKey1Bytes: pub1Vertex,
FundingScript: fn.Some(script), BitcoinKey2Bytes: pub2Vertex,
} }, models.WithFundingScript(script),
)
require.NoError(t, err)
edgePolicy := &models.ChannelEdgePolicy{ edgePolicy := &models.ChannelEdgePolicy{
SigBytes: testSig.Serialize(), SigBytes: testSig.Serialize(),
ChannelID: edge.ChannelID, ChannelID: edge.ChannelID,
@@ -274,43 +276,42 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
node1 := createTestNode(t) node1 := createTestNode(t)
node2 := createTestNode(t) node2 := createTestNode(t)
edge1 := &models.ChannelEdgeInfo{ btcKey1, err := route.NewVertexFromBytes(
Version: lnwire.GossipVersion1, bitcoinKey1.SerializeCompressed(),
ChannelID: chanID1, )
NodeKey1Bytes: node1.PubKeyBytes, require.NoError(t, err)
NodeKey2Bytes: node2.PubKeyBytes, btcKey2, err := route.NewVertexFromBytes(
AuthProof: models.NewV1ChannelAuthProof( bitcoinKey2.SerializeCompressed(),
testSig.Serialize(), )
testSig.Serialize(), require.NoError(t, err)
testSig.Serialize(),
testSig.Serialize(), edge1, err := models.NewV1Channel(
), chanID1, *chaincfg.SimNetParams.GenesisHash,
Features: lnwire.EmptyFeatureVector(), node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
FundingScript: fn.Some(fundingScript1), BitcoinKey1Bytes: btcKey1,
} BitcoinKey2Bytes: btcKey2,
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed()) }, models.WithChanProof(models.NewV1ChannelAuthProof(
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed()) testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
)), models.WithFundingScript(fundingScript1),
)
require.NoError(t, err)
if err := ctx.builder.AddEdge(ctxb, edge1); err != nil { if err := ctx.builder.AddEdge(ctxb, edge1); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
edge2 := &models.ChannelEdgeInfo{ edge2, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, chanID2, *chaincfg.SimNetParams.GenesisHash, node1.PubKeyBytes,
ChannelID: chanID2, node2.PubKeyBytes, &models.ChannelV1Fields{
NodeKey1Bytes: node1.PubKeyBytes, BitcoinKey1Bytes: btcKey1,
NodeKey2Bytes: node2.PubKeyBytes, BitcoinKey2Bytes: btcKey2,
AuthProof: models.NewV1ChannelAuthProof( }, models.WithChanProof(models.NewV1ChannelAuthProof(
testSig.Serialize(), testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), )), models.WithFundingScript(fundingScript2),
testSig.Serialize(), )
), require.NoError(t, err)
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some(fundingScript2),
}
copy(edge2.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge2.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.builder.AddEdge(ctxb, edge2); err != nil { if err := ctx.builder.AddEdge(ctxb, edge2); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
@@ -486,47 +487,39 @@ func TestDisconnectedBlocks(t *testing.T) {
node1 := createTestNode(t) node1 := createTestNode(t)
node2 := createTestNode(t) node2 := createTestNode(t)
edge1 := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(bitcoinKey1)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(bitcoinKey2)
ChannelID: chanID1,
NodeKey1Bytes: node1.PubKeyBytes, proof := models.NewV1ChannelAuthProof(
NodeKey2Bytes: node2.PubKeyBytes, testSig.Serialize(),
BitcoinKey1Bytes: node1.PubKeyBytes, testSig.Serialize(),
BitcoinKey2Bytes: node2.PubKeyBytes, testSig.Serialize(),
AuthProof: models.NewV1ChannelAuthProof( testSig.Serialize(),
testSig.Serialize(), )
testSig.Serialize(),
testSig.Serialize(), edge1, err := models.NewV1Channel(
testSig.Serialize(), chanID1, *chaincfg.SimNetParams.GenesisHash, node1.PubKeyBytes,
), node2.PubKeyBytes, &models.ChannelV1Fields{
Features: lnwire.EmptyFeatureVector(), BitcoinKey1Bytes: btcKey1,
FundingScript: fn.Some([]byte{}), BitcoinKey2Bytes: btcKey2,
} }, models.WithChanProof(proof),
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed()) models.WithFundingScript([]byte{}),
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed()) )
require.NoError(t, err)
if err := ctx.builder.AddEdge(ctxb, edge1); err != nil { if err := ctx.builder.AddEdge(ctxb, edge1); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
edge2 := &models.ChannelEdgeInfo{ edge2, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, chanID2, *chaincfg.SimNetParams.GenesisHash, node1.PubKeyBytes,
ChannelID: chanID2, node2.PubKeyBytes, &models.ChannelV1Fields{
NodeKey1Bytes: node1.PubKeyBytes, BitcoinKey1Bytes: btcKey1,
NodeKey2Bytes: node2.PubKeyBytes, BitcoinKey2Bytes: btcKey2,
BitcoinKey1Bytes: node1.PubKeyBytes, }, models.WithChanProof(proof),
BitcoinKey2Bytes: node2.PubKeyBytes, models.WithFundingScript([]byte{}),
AuthProof: models.NewV1ChannelAuthProof( )
testSig.Serialize(), require.NoError(t, err)
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
),
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some([]byte{}),
}
copy(edge2.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed())
copy(edge2.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed())
if err := ctx.builder.AddEdge(ctxb, edge2); err != nil { if err := ctx.builder.AddEdge(ctxb, edge2); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
@@ -644,24 +637,28 @@ func TestChansClosedOfflinePruneGraph(t *testing.T) {
node1 := createTestNode(t) node1 := createTestNode(t)
node2 := createTestNode(t) node2 := createTestNode(t)
edge1 := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(bitcoinKey1)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(bitcoinKey2)
ChannelID: chanID1.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes, proof := models.NewV1ChannelAuthProof(
NodeKey2Bytes: node2.PubKeyBytes, testSig.Serialize(),
AuthProof: models.NewV1ChannelAuthProof( testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), )
testSig.Serialize(),
), edge1, err := models.NewV1Channel(
ChannelPoint: *chanUTXO, chanID1.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
Capacity: chanValue, node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
Features: lnwire.EmptyFeatureVector(), BitcoinKey1Bytes: btcKey1,
FundingScript: fn.Some(script), BitcoinKey2Bytes: btcKey2,
} }, models.WithChanProof(proof),
copy(edge1.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed()) models.WithCapacity(chanValue),
copy(edge1.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed()) models.WithChannelPoint(*chanUTXO),
models.WithFundingScript(script),
)
require.NoError(t, err)
if err := ctx.builder.AddEdge(ctxb, edge1); err != nil { if err := ctx.builder.AddEdge(ctxb, edge1); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@@ -1068,17 +1065,15 @@ func TestIsStaleNode(t *testing.T) {
} }
ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
edge := &models.ChannelEdgeInfo{ edge, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
ChannelID: chanID.ToUint64(), pub1, pub2, &models.ChannelV1Fields{
NodeKey1Bytes: pub1, BitcoinKey1Bytes: pub1,
NodeKey2Bytes: pub2, BitcoinKey2Bytes: pub2,
BitcoinKey1Bytes: pub1, }, models.WithFundingScript(script),
BitcoinKey2Bytes: pub2, )
AuthProof: nil, require.NoError(t, err)
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some(script),
}
if err := ctx.builder.AddEdge(ctxb, edge); err != nil { if err := ctx.builder.AddEdge(ctxb, edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@@ -1149,17 +1144,16 @@ func TestIsKnownEdge(t *testing.T) {
} }
ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight) ctx.chain.addBlock(fundingBlock, chanID.BlockHeight, chanID.BlockHeight)
edge := &models.ChannelEdgeInfo{ edge, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash, pub1,
ChannelID: chanID.ToUint64(), pub2, &models.ChannelV1Fields{
NodeKey1Bytes: pub1, BitcoinKey1Bytes: pub1,
NodeKey2Bytes: pub2, BitcoinKey2Bytes: pub2,
BitcoinKey1Bytes: pub1, },
BitcoinKey2Bytes: pub2, models.WithFundingScript(script),
AuthProof: nil, )
FundingScript: fn.Some(script), require.NoError(t, err)
Features: lnwire.EmptyFeatureVector(),
}
if err := ctx.builder.AddEdge(ctxb, edge); err != nil { if err := ctx.builder.AddEdge(ctxb, edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@@ -1210,17 +1204,15 @@ func TestIsStaleEdgePolicy(t *testing.T) {
t.Fatalf("router failed to detect fresh edge policy") t.Fatalf("router failed to detect fresh edge policy")
} }
edge := &models.ChannelEdgeInfo{ edge, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash, pub1,
ChannelID: chanID.ToUint64(), pub2, &models.ChannelV1Fields{
NodeKey1Bytes: pub1, BitcoinKey1Bytes: pub1,
NodeKey2Bytes: pub2, BitcoinKey2Bytes: pub2,
BitcoinKey1Bytes: pub1, }, models.WithFundingScript(script),
BitcoinKey2Bytes: pub2, )
AuthProof: nil, require.NoError(t, err)
Features: lnwire.EmptyFeatureVector(),
FundingScript: fn.Some(script),
}
if err := ctx.builder.AddEdge(ctxb, edge); err != nil { if err := ctx.builder.AddEdge(ctxb, edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@@ -1523,19 +1515,27 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
// We first insert the existence of the edge between the two // We first insert the existence of the edge between the two
// nodes. // nodes.
edgeInfo := models.ChannelEdgeInfo{ var node1Vertex, node2Vertex route.Vertex
Version: lnwire.GossipVersion1, copy(node1Vertex[:], node1Bytes)
ChannelID: edge.ChannelID, copy(node2Vertex[:], node2Bytes)
AuthProof: &testAuthProof,
ChannelPoint: fundingPoint,
Capacity: btcutil.Amount(edge.Capacity),
Features: lnwire.EmptyFeatureVector(),
}
copy(edgeInfo.NodeKey1Bytes[:], node1Bytes) var btcKey1, btcKey2 route.Vertex
copy(edgeInfo.NodeKey2Bytes[:], node2Bytes) copy(btcKey1[:], node1Bytes)
copy(edgeInfo.BitcoinKey1Bytes[:], node1Bytes) copy(btcKey2[:], node2Bytes)
copy(edgeInfo.BitcoinKey2Bytes[:], node2Bytes)
edgeInfo, err := models.NewV1Channel(
edge.ChannelID, *chaincfg.SimNetParams.GenesisHash,
node1Vertex, node2Vertex, &models.ChannelV1Fields{
BitcoinKey1Bytes: btcKey1,
BitcoinKey2Bytes: btcKey2,
},
models.WithChanProof(&testAuthProof),
models.WithChannelPoint(fundingPoint),
models.WithCapacity(btcutil.Amount(edge.Capacity)),
)
if err != nil {
return nil, err
}
shortID := lnwire.NewShortChanIDFromInt(edge.ChannelID) shortID := lnwire.NewShortChanIDFromInt(edge.ChannelID)
links[shortID] = &mockLink{ links[shortID] = &mockLink{
@@ -1544,7 +1544,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
), ),
} }
err = graph.AddChannelEdge(ctx, &edgeInfo) err = graph.AddChannelEdge(ctx, edgeInfo)
if err != nil && !errors.Is(err, graphdb.ErrEdgeAlreadyExist) { if err != nil && !errors.Is(err, graphdb.ErrEdgeAlreadyExist) {
return nil, err return nil, err
} }
@@ -1584,12 +1584,12 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
} }
// We also store the channel IDs info for each of the node. // We also store the channel IDs info for each of the node.
node1Vertex, err := route.NewVertexFromBytes(node1Bytes) node1Vertex, err = route.NewVertexFromBytes(node1Bytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
node2Vertex, err := route.NewVertexFromBytes(node2Bytes) node2Vertex, err = route.NewVertexFromBytes(node2Bytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1895,21 +1895,21 @@ func createTestGraphFromChannels(t *testing.T, useCache bool,
// We first insert the existence of the edge between the two // We first insert the existence of the edge between the two
// nodes. // nodes.
edgeInfo := models.ChannelEdgeInfo{ edgeInfo, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, channelID, *chaincfg.SimNetParams.GenesisHash,
ChannelID: channelID, node1Vertex, node2Vertex, &models.ChannelV1Fields{
AuthProof: &testAuthProof, BitcoinKey1Bytes: node1Vertex,
ChannelPoint: *fundingPoint, BitcoinKey2Bytes: node2Vertex,
Capacity: testChannel.Capacity, },
models.WithChanProof(&testAuthProof),
NodeKey1Bytes: node1Vertex, models.WithChannelPoint(*fundingPoint),
BitcoinKey1Bytes: node1Vertex, models.WithCapacity(testChannel.Capacity),
NodeKey2Bytes: node2Vertex, )
BitcoinKey2Bytes: node2Vertex, if err != nil {
Features: lnwire.EmptyFeatureVector(), return nil, err
} }
err = graph.AddChannelEdge(ctx, &edgeInfo) err = graph.AddChannelEdge(ctx, edgeInfo)
if err != nil && if err != nil &&
!errors.Is(err, graphdb.ErrEdgeAlreadyExist) { !errors.Is(err, graphdb.ErrEdgeAlreadyExist) {
+10 -5
View File
@@ -4,8 +4,9 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/graph/db/models" "github.com/lightningnetwork/lnd/graph/db/models"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route"
) )
// TestChannelCache checks the behavior of the channelCache with respect to // TestChannelCache checks the behavior of the channelCache with respect to
@@ -100,10 +101,14 @@ func assertHasChanEntries(t *testing.T, c *channelCache, start, end uint64) {
// channelForInt generates a unique ChannelEdge given an integer. // channelForInt generates a unique ChannelEdge given an integer.
func channelForInt(i uint64) ChannelEdge { func channelForInt(i uint64) ChannelEdge {
info, err := models.NewV1Channel(
i, chainhash.Hash{}, route.Vertex{}, route.Vertex{},
&models.ChannelV1Fields{},
)
if err != nil {
panic(err)
}
return ChannelEdge{ return ChannelEdge{
Info: &models.ChannelEdgeInfo{ Info: info,
Version: lnwire.GossipVersion1,
ChannelID: i,
},
} }
} }
+181 -129
View File
@@ -379,7 +379,7 @@ func TestPartialNode(t *testing.T) {
// Create an edge attached to these nodes and add it to the graph. // Create an edge attached to these nodes and add it to the graph.
edgeInfo, _ := createEdge(140, 0, 0, 0, &node1, &node2) edgeInfo, _ := createEdge(140, 0, 0, 0, &node1, &node2)
require.NoError(t, graph.AddChannelEdge(ctx, &edgeInfo)) require.NoError(t, graph.AddChannelEdge(ctx, edgeInfo))
// Both of the nodes should now be in both the graph (as partial/shell) // Both of the nodes should now be in both the graph (as partial/shell)
// nodes _and_ the cache should also have an awareness of both nodes. // nodes _and_ the cache should also have an awareness of both nodes.
@@ -562,31 +562,50 @@ func TestEdgeInsertionDeletion(t *testing.T) {
require.NoError(t, err, "unable to generate node key") require.NoError(t, err, "unable to generate node key")
node2Pub, err := node2.PubKey() node2Pub, err := node2.PubKey()
require.NoError(t, err, "unable to generate node key") require.NoError(t, err, "unable to generate node key")
edgeInfo := models.ChannelEdgeInfo{
Version: lnwire.GossipVersion1,
ChannelID: chanID,
ChainHash: *chaincfg.MainNetParams.GenesisHash,
AuthProof: models.NewV1ChannelAuthProof(
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: outpoint,
Capacity: 9000,
}
copy(edgeInfo.NodeKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.NodeKey2Bytes[:], node2Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey1Bytes[:], node1Pub.SerializeCompressed())
copy(edgeInfo.BitcoinKey2Bytes[:], node2Pub.SerializeCompressed())
require.NoError(t, graph.AddChannelEdge(ctx, &edgeInfo)) node1Vertex, err := route.NewVertexFromBytes(
assertEdgeWithNoPoliciesInCache(t, graph, &edgeInfo) node1Pub.SerializeCompressed(),
)
require.NoError(t, err)
node2Vertex, err := route.NewVertexFromBytes(
node2Pub.SerializeCompressed(),
)
require.NoError(t, err)
btcKey1, err := route.NewVertexFromBytes(
node1Pub.SerializeCompressed(),
)
require.NoError(t, err)
btcKey2, err := route.NewVertexFromBytes(
node2Pub.SerializeCompressed(),
)
require.NoError(t, err)
proof := models.NewV1ChannelAuthProof(
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
)
edgeInfo, err := models.NewV1Channel(
chanID, *chaincfg.MainNetParams.GenesisHash, node1Vertex,
node2Vertex, &models.ChannelV1Fields{
BitcoinKey1Bytes: btcKey1,
BitcoinKey2Bytes: btcKey2,
},
models.WithChanProof(proof),
models.WithChannelPoint(outpoint),
models.WithCapacity(9000),
)
require.NoError(t, err)
require.NoError(t, graph.AddChannelEdge(ctx, edgeInfo))
assertEdgeWithNoPoliciesInCache(t, graph, edgeInfo)
// Show that trying to insert the same channel again will return the // Show that trying to insert the same channel again will return the
// expected error. // expected error.
err = graph.AddChannelEdge(ctx, &edgeInfo) err = graph.AddChannelEdge(ctx, edgeInfo)
require.ErrorIs(t, err, ErrEdgeAlreadyExist) require.ErrorIs(t, err, ErrEdgeAlreadyExist)
// Ensure that both policies are returned as unknown (nil). // Ensure that both policies are returned as unknown (nil).
@@ -623,7 +642,7 @@ func TestEdgeInsertionDeletion(t *testing.T) {
} }
func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32, func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32,
node1, node2 *models.Node) (models.ChannelEdgeInfo, node1, node2 *models.Node) (*models.ChannelEdgeInfo,
lnwire.ShortChannelID) { lnwire.ShortChannelID) {
shortChanID := lnwire.ShortChannelID{ shortChanID := lnwire.ShortChannelID{
@@ -638,26 +657,37 @@ func createEdge(height, txIndex uint32, txPosition uint16, outPointIndex uint32,
node1Pub, _ := node1.PubKey() node1Pub, _ := node1.PubKey()
node2Pub, _ := node2.PubKey() node2Pub, _ := node2.PubKey()
edgeInfo := models.ChannelEdgeInfo{
Version: lnwire.GossipVersion1,
ChannelID: shortChanID.ToUint64(),
ChainHash: *chaincfg.MainNetParams.GenesisHash,
AuthProof: models.NewV1ChannelAuthProof(
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
),
ChannelPoint: outpoint,
Capacity: 9000,
ExtraOpaqueData: make([]byte, 0),
Features: lnwire.EmptyFeatureVector(),
}
copy(edgeInfo.NodeKey1Bytes[:], node1Pub.SerializeCompressed()) node1Vertex, _ := route.NewVertexFromBytes(
copy(edgeInfo.NodeKey2Bytes[:], node2Pub.SerializeCompressed()) node1Pub.SerializeCompressed(),
copy(edgeInfo.BitcoinKey1Bytes[:], node1Pub.SerializeCompressed()) )
copy(edgeInfo.BitcoinKey2Bytes[:], node2Pub.SerializeCompressed()) node2Vertex, _ := route.NewVertexFromBytes(
node2Pub.SerializeCompressed(),
)
btcKey1, _ := route.NewVertexFromBytes(
node1Pub.SerializeCompressed(),
)
btcKey2, _ := route.NewVertexFromBytes(
node2Pub.SerializeCompressed(),
)
proof := models.NewV1ChannelAuthProof(
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
)
edgeInfo, _ := models.NewV1Channel(
shortChanID.ToUint64(), *chaincfg.MainNetParams.GenesisHash,
node1Vertex, node2Vertex, &models.ChannelV1Fields{
BitcoinKey1Bytes: btcKey1,
BitcoinKey2Bytes: btcKey2,
ExtraOpaqueData: make([]byte, 0),
},
models.WithChanProof(proof), models.WithChannelPoint(outpoint),
models.WithCapacity(9000),
)
return edgeInfo, shortChanID return edgeInfo, shortChanID
} }
@@ -716,20 +746,20 @@ func TestDisconnectBlockAtHeight(t *testing.T) {
edgeInfo3, _ := createEdge(height-1, 0, 0, 2, node1, node2) edgeInfo3, _ := createEdge(height-1, 0, 0, 2, node1, node2)
// Now add all these new edges to the database. // Now add all these new edges to the database.
if err := graph.AddChannelEdge(ctx, &edgeInfo); err != nil { if err := graph.AddChannelEdge(ctx, edgeInfo); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
if err := graph.AddChannelEdge(ctx, &edgeInfo2); err != nil { if err := graph.AddChannelEdge(ctx, edgeInfo2); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
if err := graph.AddChannelEdge(ctx, &edgeInfo3); err != nil { if err := graph.AddChannelEdge(ctx, edgeInfo3); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
assertEdgeWithNoPoliciesInCache(t, graph, &edgeInfo) assertEdgeWithNoPoliciesInCache(t, graph, edgeInfo)
assertEdgeWithNoPoliciesInCache(t, graph, &edgeInfo2) assertEdgeWithNoPoliciesInCache(t, graph, edgeInfo2)
assertEdgeWithNoPoliciesInCache(t, graph, &edgeInfo3) assertEdgeWithNoPoliciesInCache(t, graph, edgeInfo3)
// Call DisconnectBlockAtHeight, which should prune every channel // Call DisconnectBlockAtHeight, which should prune every channel
// that has a funding height of 'height' or greater. // that has a funding height of 'height' or greater.
@@ -739,7 +769,7 @@ func TestDisconnectBlockAtHeight(t *testing.T) {
} }
assertNoEdge(t, graph, edgeInfo.ChannelID) assertNoEdge(t, graph, edgeInfo.ChannelID)
assertNoEdge(t, graph, edgeInfo2.ChannelID) assertNoEdge(t, graph, edgeInfo2.ChannelID)
assertEdgeWithNoPoliciesInCache(t, graph, &edgeInfo3) assertEdgeWithNoPoliciesInCache(t, graph, edgeInfo3)
// The two edges should have been removed. // The two edges should have been removed.
if len(removed) != 2 { if len(removed) != 2 {
@@ -898,35 +928,50 @@ func createChannelEdge(node1, node2 *models.Node,
// Add the new edge to the database, this should proceed without any // Add the new edge to the database, this should proceed without any
// errors. // errors.
edgeInfo := &models.ChannelEdgeInfo{ var node1Key, node2Key route.Vertex
Version: lnwire.GossipVersion1, copy(node1Key[:], firstNode[:])
ChannelID: chanID, copy(node2Key[:], secondNode[:])
ChainHash: *chaincfg.MainNetParams.GenesisHash,
ChannelPoint: outpoint,
Capacity: 1000,
ExtraOpaqueData: []byte{
1, 1, 1,
2, 2, 2, 2,
3, 3, 3, 3, 3,
},
Features: lnwire.EmptyFeatureVector(),
}
copy(edgeInfo.NodeKey1Bytes[:], firstNode[:])
copy(edgeInfo.NodeKey2Bytes[:], secondNode[:])
copy(edgeInfo.BitcoinKey1Bytes[:], firstNode[:])
copy(edgeInfo.BitcoinKey2Bytes[:], secondNode[:])
extraData := []byte{
1, 1, 1,
2, 2, 2, 2,
3, 3, 3, 3, 3,
}
var edgeInfo *models.ChannelEdgeInfo
if opts.skipProofs { if opts.skipProofs {
edgeInfo, _ = models.NewV1Channel(
chanID, *chaincfg.MainNetParams.GenesisHash, node1Key,
node2Key, &models.ChannelV1Fields{
BitcoinKey1Bytes: node1Key,
BitcoinKey2Bytes: node2Key,
ExtraOpaqueData: extraData,
}, models.WithChannelPoint(outpoint),
models.WithCapacity(1000),
)
return edgeInfo, nil, nil return edgeInfo, nil, nil
} }
edgeInfo.AuthProof = models.NewV1ChannelAuthProof( proof := models.NewV1ChannelAuthProof(
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
) )
edgeInfo, _ = models.NewV1Channel(
chanID, *chaincfg.MainNetParams.GenesisHash, node1Key, node2Key,
&models.ChannelV1Fields{
BitcoinKey1Bytes: node1Key,
BitcoinKey2Bytes: node2Key,
ExtraOpaqueData: extraData,
},
models.WithChanProof(proof),
models.WithChannelPoint(outpoint),
models.WithCapacity(1000),
)
edge1 := &models.ChannelEdgePolicy{ edge1 := &models.ChannelEdgePolicy{
SigBytes: testSig.Serialize(), SigBytes: testSig.Serialize(),
ChannelID: chanID, ChannelID: chanID,
@@ -1780,25 +1825,29 @@ func fillTestGraph(t testing.TB, graph *ChannelGraph, numNodes,
Index: 0, Index: 0,
} }
edgeInfo := models.ChannelEdgeInfo{ var node1Key, node2Key route.Vertex
Version: lnwire.GossipVersion1, copy(node1Key[:], node1.PubKeyBytes[:])
ChannelID: chanID, copy(node2Key[:], node2.PubKeyBytes[:])
ChainHash: *chaincfg.MainNetParams.GenesisHash,
AuthProof: models.NewV1ChannelAuthProof( proof := models.NewV1ChannelAuthProof(
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
), )
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: op, edgeInfo, err := models.NewV1Channel(
Capacity: 1000, chanID, *chaincfg.MainNetParams.GenesisHash,
} node1Key, node2Key, &models.ChannelV1Fields{
copy(edgeInfo.NodeKey1Bytes[:], node1.PubKeyBytes[:]) BitcoinKey1Bytes: node1Key,
copy(edgeInfo.NodeKey2Bytes[:], node2.PubKeyBytes[:]) BitcoinKey2Bytes: node2Key,
copy(edgeInfo.BitcoinKey1Bytes[:], node1.PubKeyBytes[:]) },
copy(edgeInfo.BitcoinKey2Bytes[:], node2.PubKeyBytes[:]) models.WithChanProof(proof),
err := graph.AddChannelEdge(ctx, &edgeInfo) models.WithChannelPoint(op),
models.WithCapacity(1000),
)
require.NoError(t, err)
err = graph.AddChannelEdge(ctx, edgeInfo)
require.NoError(t, err) require.NoError(t, err)
// Create and add an edge with random data that points // Create and add an edge with random data that points
@@ -1963,28 +2012,31 @@ func TestGraphPruning(t *testing.T) {
channelPoints = append(channelPoints, &op) channelPoints = append(channelPoints, &op)
edgeInfo := models.ChannelEdgeInfo{ var node1Key, node2Key route.Vertex
Version: lnwire.GossipVersion1, copy(node1Key[:], graphNodes[i].PubKeyBytes[:])
ChannelID: chanID, copy(node2Key[:], graphNodes[i+1].PubKeyBytes[:])
ChainHash: *chaincfg.MainNetParams.GenesisHash,
AuthProof: models.NewV1ChannelAuthProof( proof := models.NewV1ChannelAuthProof(
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
),
Features: lnwire.EmptyFeatureVector(),
ChannelPoint: op,
Capacity: 1000,
}
copy(edgeInfo.NodeKey1Bytes[:], graphNodes[i].PubKeyBytes[:])
copy(edgeInfo.NodeKey2Bytes[:], graphNodes[i+1].PubKeyBytes[:])
copy(edgeInfo.BitcoinKey1Bytes[:], graphNodes[i].PubKeyBytes[:])
copy(
edgeInfo.BitcoinKey2Bytes[:],
graphNodes[i+1].PubKeyBytes[:],
) )
if err := graph.AddChannelEdge(ctx, &edgeInfo); err != nil {
edgeInfo, err := models.NewV1Channel(
chanID, *chaincfg.MainNetParams.GenesisHash,
node1Key, node2Key, &models.ChannelV1Fields{
BitcoinKey1Bytes: node1Key,
BitcoinKey2Bytes: node2Key,
},
models.WithChanProof(proof),
models.WithChannelPoint(op),
models.WithCapacity(1000),
)
if err != nil {
t.Fatalf("unable to create edge: %v", err)
}
if err := graph.AddChannelEdge(ctx, edgeInfo); err != nil {
t.Fatalf("unable to add node: %v", err) t.Fatalf("unable to add node: %v", err)
} }
@@ -2140,10 +2192,10 @@ func TestHighestChanID(t *testing.T) {
edge1, _ := createEdge(10, 0, 0, 0, node1, node2) edge1, _ := createEdge(10, 0, 0, 0, node1, node2)
edge2, chanID2 := createEdge(100, 0, 0, 0, node1, node2) edge2, chanID2 := createEdge(100, 0, 0, 0, node1, node2)
if err := graph.AddChannelEdge(ctx, &edge1); err != nil { if err := graph.AddChannelEdge(ctx, edge1); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
if err := graph.AddChannelEdge(ctx, &edge2); err != nil { if err := graph.AddChannelEdge(ctx, edge2); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
@@ -2160,7 +2212,7 @@ func TestHighestChanID(t *testing.T) {
// If we add another edge, then the current best chan ID should be // If we add another edge, then the current best chan ID should be
// updated as well. // updated as well.
edge3, chanID3 := createEdge(1000, 0, 0, 0, node1, node2) edge3, chanID3 := createEdge(1000, 0, 0, 0, node1, node2)
if err := graph.AddChannelEdge(ctx, &edge3); err != nil { if err := graph.AddChannelEdge(ctx, edge3); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
bestID, err = graph.HighestChanID(ctx) bestID, err = graph.HighestChanID(ctx)
@@ -2216,7 +2268,7 @@ func TestChanUpdatesInHorizon(t *testing.T) {
uint32(i*10), 0, 0, 0, node1, node2, uint32(i*10), 0, 0, 0, node1, node2,
) )
if err := graph.AddChannelEdge(ctx, &channel); err != nil { if err := graph.AddChannelEdge(ctx, channel); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
@@ -2245,7 +2297,7 @@ func TestChanUpdatesInHorizon(t *testing.T) {
} }
edges = append(edges, ChannelEdge{ edges = append(edges, ChannelEdge{
Info: &channel, Info: channel,
Policy1: edge1, Policy1: edge1,
Policy2: edge2, Policy2: edge2,
}) })
@@ -2683,7 +2735,7 @@ func TestChanUpdatesInHorizonBoundaryConditions(t *testing.T) {
uint32(i*10), 0, 0, 0, node1, node2, uint32(i*10), 0, 0, 0, node1, node2,
) )
require.NoError( require.NoError(
t, graph.AddChannelEdge(ctx, &channel), t, graph.AddChannelEdge(ctx, channel),
) )
edge1 := newEdgePolicy( edge1 := newEdgePolicy(
@@ -2851,7 +2903,7 @@ func TestFilterKnownChanIDs(t *testing.T) {
uint32(i*10), 0, 0, 0, node1, node2, uint32(i*10), 0, 0, 0, node1, node2,
) )
if err := graph.AddChannelEdge(ctx, &channel); err != nil { if err := graph.AddChannelEdge(ctx, channel); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
@@ -2866,7 +2918,7 @@ func TestFilterKnownChanIDs(t *testing.T) {
channel, chanID := createEdge( channel, chanID := createEdge(
uint32(i*10+1), 0, 0, 0, node1, node2, uint32(i*10+1), 0, 0, 0, node1, node2,
) )
if err := graph.AddChannelEdge(ctx, &channel); err != nil { if err := graph.AddChannelEdge(ctx, channel); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
err := graph.DeleteChannelEdges(false, true, channel.ChannelID) err := graph.DeleteChannelEdges(false, true, channel.ChannelID)
@@ -3027,7 +3079,7 @@ func TestStressTestChannelGraphAPI(t *testing.T) {
) )
newChan := &chanInfo{ newChan := &chanInfo{
info: channel, info: *channel,
id: chanID, id: chanID,
} }
chans = append(chans, newChan) chans = append(chans, newChan)
@@ -3339,12 +3391,12 @@ func TestFilterChannelRange(t *testing.T) {
channel1, chanID1 := createEdge( channel1, chanID1 := createEdge(
chanHeight, uint32(i+1), 0, 0, node1, node2, chanHeight, uint32(i+1), 0, 0, node1, node2,
) )
require.NoError(t, graph.AddChannelEdge(ctx, &channel1)) require.NoError(t, graph.AddChannelEdge(ctx, channel1))
channel2, chanID2 := createEdge( channel2, chanID2 := createEdge(
chanHeight, uint32(i+2), 0, 0, node1, node2, chanHeight, uint32(i+2), 0, 0, node1, node2,
) )
require.NoError(t, graph.AddChannelEdge(ctx, &channel2)) require.NoError(t, graph.AddChannelEdge(ctx, channel2))
chanInfo1 := NewChannelUpdateInfo( chanInfo1 := NewChannelUpdateInfo(
chanID1, time.Time{}, time.Time{}, chanID1, time.Time{}, time.Time{},
@@ -3520,7 +3572,7 @@ func TestFetchChanInfos(t *testing.T) {
uint32(i*10), 0, 0, 0, node1, node2, uint32(i*10), 0, 0, 0, node1, node2,
) )
if err := graph.AddChannelEdge(ctx, &channel); err != nil { if err := graph.AddChannelEdge(ctx, channel); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
@@ -3544,7 +3596,7 @@ func TestFetchChanInfos(t *testing.T) {
} }
edges = append(edges, ChannelEdge{ edges = append(edges, ChannelEdge{
Info: &channel, Info: channel,
Policy1: edge1, Policy1: edge1,
Policy2: edge2, Policy2: edge2,
}) })
@@ -3561,7 +3613,7 @@ func TestFetchChanInfos(t *testing.T) {
zombieChan, zombieChanID := createEdge( zombieChan, zombieChanID := createEdge(
666, 0, 0, 0, node1, node2, 666, 0, 0, 0, node1, node2,
) )
if err := graph.AddChannelEdge(ctx, &zombieChan); err != nil { if err := graph.AddChannelEdge(ctx, zombieChan); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
err := graph.DeleteChannelEdges(false, true, zombieChan.ChannelID) err := graph.DeleteChannelEdges(false, true, zombieChan.ChannelID)
@@ -3614,7 +3666,7 @@ func TestIncompleteChannelPolicies(t *testing.T) {
uint32(0), 0, 0, 0, node1, node2, uint32(0), 0, 0, 0, node1, node2,
) )
if err := graph.AddChannelEdge(ctx, &channel); err != nil { if err := graph.AddChannelEdge(ctx, channel); err != nil {
t.Fatalf("unable to create channel edge: %v", err) t.Fatalf("unable to create channel edge: %v", err)
} }
@@ -3718,7 +3770,7 @@ func TestChannelEdgePruningUpdateIndexDeletion(t *testing.T) {
// With the two nodes created, we'll now create a random channel, as // With the two nodes created, we'll now create a random channel, as
// well as two edges in the database with distinct update times. // well as two edges in the database with distinct update times.
edgeInfo, chanID := createEdge(100, 0, 0, 0, node1, node2) edgeInfo, chanID := createEdge(100, 0, 0, 0, node1, node2)
if err := graph.AddChannelEdge(ctx, &edgeInfo); err != nil { if err := graph.AddChannelEdge(ctx, edgeInfo); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@@ -3867,7 +3919,7 @@ func TestPruneGraphNodes(t *testing.T) {
// We'll now add a new edge to the graph, but only actually advertise // We'll now add a new edge to the graph, but only actually advertise
// the edge of *one* of the nodes. // the edge of *one* of the nodes.
edgeInfo, chanID := createEdge(100, 0, 0, 0, node1, node2) edgeInfo, chanID := createEdge(100, 0, 0, 0, node1, node2)
if err := graph.AddChannelEdge(ctx, &edgeInfo); err != nil { if err := graph.AddChannelEdge(ctx, edgeInfo); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@@ -3916,7 +3968,7 @@ func TestAddChannelEdgeShellNodes(t *testing.T) {
// We'll now create an edge between the two nodes, as a result, node2 // We'll now create an edge between the two nodes, as a result, node2
// should be inserted into the database as a shell node. // should be inserted into the database as a shell node.
edgeInfo, _ := createEdge(100, 0, 0, 0, node1, node2) edgeInfo, _ := createEdge(100, 0, 0, 0, node1, node2)
require.NoError(t, graph.AddChannelEdge(ctx, &edgeInfo)) require.NoError(t, graph.AddChannelEdge(ctx, edgeInfo))
// Ensure that node1 was inserted as a full node, while node2 only has // Ensure that node1 was inserted as a full node, while node2 only has
// a shell node present. // a shell node present.
@@ -3930,7 +3982,7 @@ func TestAddChannelEdgeShellNodes(t *testing.T) {
// Show that attempting to add the channel again will result in an // Show that attempting to add the channel again will result in an
// error. // error.
err = graph.AddChannelEdge(ctx, &edgeInfo) err = graph.AddChannelEdge(ctx, edgeInfo)
require.ErrorIs(t, err, ErrEdgeAlreadyExist) require.ErrorIs(t, err, ErrEdgeAlreadyExist)
// Show that updating the shell node to a full node record works. // Show that updating the shell node to a full node record works.
@@ -4049,7 +4101,7 @@ func TestNodeIsPublic(t *testing.T) {
// After creating all of our nodes and edges, we'll add them to each // After creating all of our nodes and edges, we'll add them to each
// participant's graph. // participant's graph.
nodes := []*models.Node{aliceNode, bobNode, carolNode} nodes := []*models.Node{aliceNode, bobNode, carolNode}
edges := []*models.ChannelEdgeInfo{&aliceBobEdge, &bobCarolEdge} edges := []*models.ChannelEdgeInfo{aliceBobEdge, bobCarolEdge}
graphs := []*ChannelGraph{aliceGraph, bobGraph, carolGraph} graphs := []*ChannelGraph{aliceGraph, bobGraph, carolGraph}
for _, graph := range graphs { for _, graph := range graphs {
for _, node := range nodes { for _, node := range nodes {
@@ -4131,7 +4183,7 @@ func TestNodeIsPublic(t *testing.T) {
} }
bobCarolEdge.AuthProof = nil bobCarolEdge.AuthProof = nil
if err := graph.AddChannelEdge(ctx, &bobCarolEdge); err != nil { if err := graph.AddChannelEdge(ctx, bobCarolEdge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
} }
@@ -4634,7 +4686,7 @@ func TestBatchedAddChannelEdge(t *testing.T) {
// Create a third edge, this with a block height of 155. // Create a third edge, this with a block height of 155.
edgeInfo3, _ := createEdge(height-1, 0, 0, 2, node1, node2) edgeInfo3, _ := createEdge(height-1, 0, 0, 2, node1, node2)
edges := []models.ChannelEdgeInfo{edgeInfo, edgeInfo2, edgeInfo3} edges := []models.ChannelEdgeInfo{*edgeInfo, *edgeInfo2, *edgeInfo3}
errChan := make(chan error, len(edges)) errChan := make(chan error, len(edges))
errTimeout := errors.New("timeout adding batched channel") errTimeout := errors.New("timeout adding batched channel")
+7 -4
View File
@@ -3950,11 +3950,14 @@ func (c *KVStore) FetchChannelEdgesByID(chanID uint64) (
// populate the edge info with the public keys of each // populate the edge info with the public keys of each
// party as this is the only information we have about // party as this is the only information we have about
// it and return an error signaling so. // it and return an error signaling so.
edgeInfo = &models.ChannelEdgeInfo{ zombieEdge, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, 0, chainhash.Hash{}, pubKey1, pubKey2,
NodeKey1Bytes: pubKey1, &models.ChannelV1Fields{},
NodeKey2Bytes: pubKey2, )
if err != nil {
return err
} }
edgeInfo = zombieEdge
return ErrZombieEdge return ErrZombieEdge
} }
+93
View File
@@ -76,6 +76,99 @@ type ChannelEdgeInfo struct {
ExtraOpaqueData []byte ExtraOpaqueData []byte
} }
// EdgeModifier is a functional option that modifies a ChannelEdgeInfo.
type EdgeModifier func(*ChannelEdgeInfo)
// WithChannelPoint sets the channel point (funding outpoint) on the edge.
func WithChannelPoint(cp wire.OutPoint) EdgeModifier {
return func(e *ChannelEdgeInfo) {
e.ChannelPoint = cp
}
}
// WithFeatures sets the feature vector on the edge.
func WithFeatures(f *lnwire.RawFeatureVector) EdgeModifier {
return func(e *ChannelEdgeInfo) {
e.Features = lnwire.NewFeatureVector(f, lnwire.Features)
}
}
// WithCapacity sets the capacity on the edge.
func WithCapacity(c btcutil.Amount) EdgeModifier {
return func(e *ChannelEdgeInfo) {
e.Capacity = c
}
}
// WithChanProof sets the authentication proof on the edge.
func WithChanProof(proof *ChannelAuthProof) EdgeModifier {
return func(e *ChannelEdgeInfo) {
e.AuthProof = proof
}
}
// WithFundingScript sets the funding script on the edge.
func WithFundingScript(script []byte) EdgeModifier {
return func(e *ChannelEdgeInfo) {
e.FundingScript = fn.Some(script)
}
}
// ChannelV1Fields contains the fields that are specific to v1 channel
// announcements.
type ChannelV1Fields struct {
// BitcoinKey1Bytes is the raw public key of the first node.
BitcoinKey1Bytes route.Vertex
// BitcoinKey2Bytes is the raw public key of the second node.
BitcoinKey2Bytes route.Vertex
// ExtraOpaqueData is the set of data that was appended to this
// message, some of which we may not actually know how to iterate or
// parse. By holding onto this data, we ensure that we're able to
// properly validate the set of signatures that cover these new fields,
// and ensure we're able to make upgrades to the network in a forwards
// compatible manner.
ExtraOpaqueData []byte
}
// NewV1Channel creates a new ChannelEdgeInfo for a v1 channel announcement.
// It takes the required fields for all channels (chanID, chainHash, node keys)
// and v1-specific fields, along with optional modifiers for setting additional
// fields like capacity, channel point, features, and auth proof.
//
// The constructor validates that if an AuthProof is provided via modifiers, its
// version matches the channel version (v1).
func NewV1Channel(chanID uint64, chainHash chainhash.Hash, node1,
node2 route.Vertex, v1Fields *ChannelV1Fields,
opts ...EdgeModifier) (*ChannelEdgeInfo, error) {
edge := &ChannelEdgeInfo{
Version: lnwire.GossipVersion1,
NodeKey1Bytes: node1,
NodeKey2Bytes: node2,
BitcoinKey1Bytes: v1Fields.BitcoinKey1Bytes,
BitcoinKey2Bytes: v1Fields.BitcoinKey2Bytes,
ChannelID: chanID,
ChainHash: chainHash,
Features: lnwire.EmptyFeatureVector(),
ExtraOpaqueData: v1Fields.ExtraOpaqueData,
}
for _, opt := range opts {
opt(edge)
}
// Validate some fields after the options have been applied.
if edge.AuthProof != nil && edge.AuthProof.Version != edge.Version {
return nil, fmt.Errorf("channel auth proof version %d does "+
"not match channel version %d", edge.AuthProof.Version,
edge.Version)
}
return edge, nil
}
// NodeKey1 is the identity public key of the "first" node that was involved in // NodeKey1 is the identity public key of the "first" node that was involved in
// the creation of this channel. A node is considered "first" if the // the creation of this channel. A node is considered "first" if the
// lexicographical ordering the its serialized public key is "smaller" than // lexicographical ordering the its serialized public key is "smaller" than
+36 -19
View File
@@ -2038,11 +2038,22 @@ func (s *SQLStore) FetchChannelEdgesByID(chanID uint64) (
// populate the edge info with the public keys of each // populate the edge info with the public keys of each
// party as this is the only information we have about // party as this is the only information we have about
// it. // it.
edge = &models.ChannelEdgeInfo{ node1, err := route.NewVertexFromBytes(zombie.NodeKey1)
Version: lnwire.GossipVersion1, if err != nil {
return err
} }
copy(edge.NodeKey1Bytes[:], zombie.NodeKey1) node2, err := route.NewVertexFromBytes(zombie.NodeKey2)
copy(edge.NodeKey2Bytes[:], zombie.NodeKey2) if err != nil {
return err
}
zombieEdge, err := models.NewV1Channel(
0, chainhash.Hash{}, node1, node2,
&models.ChannelV1Fields{},
)
if err != nil {
return err
}
edge = zombieEdge
return ErrZombieEdge return ErrZombieEdge
} else if err != nil { } else if err != nil {
@@ -4467,22 +4478,28 @@ func buildEdgeInfoWithBatchData(chain chainhash.Hash,
recs = make([]byte, 0) recs = make([]byte, 0)
} }
var btcKey1, btcKey2 route.Vertex btcKey1, err := route.NewVertexFromBytes(dbChan.BitcoinKey1)
copy(btcKey1[:], dbChan.BitcoinKey1) if err != nil {
copy(btcKey2[:], dbChan.BitcoinKey2) return nil, err
}
btcKey2, err := route.NewVertexFromBytes(dbChan.BitcoinKey2)
if err != nil {
return nil, err
}
channel := &models.ChannelEdgeInfo{ channel, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, byteOrder.Uint64(dbChan.Scid), chain, node1, node2,
ChainHash: chain, &models.ChannelV1Fields{
ChannelID: byteOrder.Uint64(dbChan.Scid), BitcoinKey1Bytes: btcKey1,
NodeKey1Bytes: node1, BitcoinKey2Bytes: btcKey2,
NodeKey2Bytes: node2, ExtraOpaqueData: recs,
BitcoinKey1Bytes: btcKey1, },
BitcoinKey2Bytes: btcKey2, models.WithChannelPoint(*op),
ChannelPoint: *op, models.WithCapacity(btcutil.Amount(dbChan.Capacity.Int64)),
Capacity: btcutil.Amount(dbChan.Capacity.Int64), models.WithFeatures(fv.RawFeatureVector),
Features: fv, )
ExtraOpaqueData: recs, if err != nil {
return nil, err
} }
// We always set all the signatures at the same time, so we can // We always set all the signatures at the same time, so we can
+85 -70
View File
@@ -14,6 +14,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
@@ -447,24 +448,27 @@ func TestEdgeUpdateNotification(t *testing.T) {
// Finally, to conclude our test set up, we'll create a channel // Finally, to conclude our test set up, we'll create a channel
// update to announce the created channel between the two nodes. // update to announce the created channel between the two nodes.
edge := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(bitcoinKey1)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(bitcoinKey2)
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes, proof := models.NewV1ChannelAuthProof(
NodeKey2Bytes: node2.PubKeyBytes, testSig.Serialize(),
AuthProof: models.NewV1ChannelAuthProof( testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), )
testSig.Serialize(),
), edge, err := models.NewV1Channel(
Features: lnwire.EmptyFeatureVector(), chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
ChannelPoint: *chanPoint, node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
Capacity: chanValue, BitcoinKey1Bytes: btcKey1,
FundingScript: fn.Some(script), BitcoinKey2Bytes: btcKey2,
} }, models.WithChanProof(proof),
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed()) models.WithChannelPoint(*chanPoint),
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed()) models.WithCapacity(chanValue),
models.WithFundingScript(script),
)
require.NoError(t, err)
if err := ctx.builder.AddEdge(ctxb, edge); err != nil { if err := ctx.builder.AddEdge(ctxb, edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
@@ -642,22 +646,25 @@ func TestNodeUpdateNotification(t *testing.T) {
testFeaturesBuf := new(bytes.Buffer) testFeaturesBuf := new(bytes.Buffer)
require.NoError(t, testFeatures.Encode(testFeaturesBuf)) require.NoError(t, testFeatures.Encode(testFeaturesBuf))
edge := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(bitcoinKey1)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(bitcoinKey2)
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes, proof := models.NewV1ChannelAuthProof(
NodeKey2Bytes: node2.PubKeyBytes, testSig.Serialize(),
Features: lnwire.EmptyFeatureVector(), testSig.Serialize(),
AuthProof: models.NewV1ChannelAuthProof( testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), )
testSig.Serialize(),
testSig.Serialize(), edge, err := models.NewV1Channel(
), chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
FundingScript: fn.Some(script), node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
} BitcoinKey1Bytes: btcKey1,
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed()) BitcoinKey2Bytes: btcKey2,
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed()) }, models.WithChanProof(proof),
models.WithFundingScript(script),
)
require.NoError(t, err)
// Adding the edge will add the nodes to the graph, but with no info // Adding the edge will add the nodes to the graph, but with no info
// except the pubkey known. // except the pubkey known.
@@ -829,24 +836,28 @@ func TestNotificationCancellation(t *testing.T) {
// to the client. // to the client.
ntfnClient.Cancel() ntfnClient.Cancel()
edge := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(bitcoinKey1)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(bitcoinKey2)
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes, proof := models.NewV1ChannelAuthProof(
NodeKey2Bytes: node2.PubKeyBytes, testSig.Serialize(),
AuthProof: models.NewV1ChannelAuthProof( testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), )
testSig.Serialize(),
), edge, err := models.NewV1Channel(
Features: lnwire.EmptyFeatureVector(), chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
ChannelPoint: *chanPoint, node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
Capacity: chanValue, BitcoinKey1Bytes: btcKey1,
FundingScript: fn.Some(script), BitcoinKey2Bytes: btcKey2,
} }, models.WithChanProof(proof),
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed()) models.WithChannelPoint(*chanPoint),
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed()) models.WithCapacity(chanValue),
models.WithFundingScript(script),
)
require.NoError(t, err)
if err := ctx.builder.AddEdge(ctxb, edge); err != nil { if err := ctx.builder.AddEdge(ctxb, edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
@@ -906,24 +917,28 @@ func TestChannelCloseNotification(t *testing.T) {
// Finally, to conclude our test set up, we'll create a channel // Finally, to conclude our test set up, we'll create a channel
// announcement to announce the created channel between the two nodes. // announcement to announce the created channel between the two nodes.
edge := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(bitcoinKey1)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(bitcoinKey2)
ChannelID: chanID.ToUint64(),
NodeKey1Bytes: node1.PubKeyBytes, proof := models.NewV1ChannelAuthProof(
NodeKey2Bytes: node2.PubKeyBytes, testSig.Serialize(),
AuthProof: models.NewV1ChannelAuthProof( testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), )
testSig.Serialize(),
), edge, err := models.NewV1Channel(
Features: lnwire.EmptyFeatureVector(), chanID.ToUint64(), *chaincfg.SimNetParams.GenesisHash,
ChannelPoint: *chanUtxo, node1.PubKeyBytes, node2.PubKeyBytes, &models.ChannelV1Fields{
Capacity: chanValue, BitcoinKey1Bytes: btcKey1,
FundingScript: fn.Some(script), BitcoinKey2Bytes: btcKey2,
} }, models.WithChanProof(proof),
copy(edge.BitcoinKey1Bytes[:], bitcoinKey1.SerializeCompressed()) models.WithChannelPoint(*chanUtxo),
copy(edge.BitcoinKey2Bytes[:], bitcoinKey2.SerializeCompressed()) models.WithCapacity(chanValue),
models.WithFundingScript(script),
)
require.NoError(t, err)
if err := ctx.builder.AddEdge(ctxb, edge); err != nil { if err := ctx.builder.AddEdge(ctxb, edge); err != nil {
t.Fatalf("unable to add edge: %v", err) t.Fatalf("unable to add edge: %v", err)
} }
+12 -11
View File
@@ -224,7 +224,6 @@ func (s *Server) ImportGraph(ctx context.Context,
// Obtain the pointer to the global singleton channel graph. // Obtain the pointer to the global singleton channel graph.
graphDB := s.cfg.GraphDB graphDB := s.cfg.GraphDB
var err error
for _, rpcNode := range graph.Nodes { for _, rpcNode := range graph.Nodes {
pubKeyBytes, err := parsePubKey(rpcNode.PubKey) pubKeyBytes, err := parsePubKey(rpcNode.PubKey)
if err != nil { if err != nil {
@@ -273,19 +272,12 @@ func (s *Server) ImportGraph(ctx context.Context,
for _, rpcEdge := range graph.Edges { for _, rpcEdge := range graph.Edges {
rpcEdge := rpcEdge rpcEdge := rpcEdge
edge := &models.ChannelEdgeInfo{ node1, err := parsePubKey(rpcEdge.Node1Pub)
Version: lnwire.GossipVersion1,
ChannelID: rpcEdge.ChannelId,
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
Capacity: btcutil.Amount(rpcEdge.Capacity),
}
edge.NodeKey1Bytes, err = parsePubKey(rpcEdge.Node1Pub)
if err != nil { if err != nil {
return nil, err return nil, err
} }
edge.NodeKey2Bytes, err = parsePubKey(rpcEdge.Node2Pub) node2, err := parsePubKey(rpcEdge.Node2Pub)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -294,7 +286,16 @@ func (s *Server) ImportGraph(ctx context.Context,
if err != nil { if err != nil {
return nil, err return nil, err
} }
edge.ChannelPoint = *channelPoint
edge, err := models.NewV1Channel(
rpcEdge.ChannelId, *s.cfg.ActiveNetParams.GenesisHash,
node1, node2, &models.ChannelV1Fields{},
models.WithCapacity(btcutil.Amount(rpcEdge.Capacity)),
models.WithChannelPoint(*channelPoint),
)
if err != nil {
return nil, err
}
if err := graphDB.AddChannelEdge(ctx, edge); err != nil { if err := graphDB.AddChannelEdge(ctx, edge); err != nil {
return nil, fmt.Errorf("unable to add edge %v: %w", return nil, fmt.Errorf("unable to add edge %v: %w",
+12 -4
View File
@@ -6,10 +6,12 @@ import (
"testing" "testing"
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/graph/db/models" "github.com/lightningnetwork/lnd/graph/db/models"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/zpay32" "github.com/lightningnetwork/lnd/zpay32"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -305,10 +307,16 @@ var shouldIncludeChannelTestCases = []struct {
h.Mock.On( h.Mock.On(
"FetchChannelEdgesByID", mock.Anything, "FetchChannelEdgesByID", mock.Anything,
).Once().Return( ).Once().Return(
&models.ChannelEdgeInfo{ func() *models.ChannelEdgeInfo {
Version: lnwire.GossipVersion1, edge, err := models.NewV1Channel(
NodeKey1Bytes: selectedPolicy, 0, chainhash.Hash{}, selectedPolicy,
}, route.Vertex{},
&models.ChannelV1Fields{},
)
require.NoError(h.t, err)
return edge
}(),
&models.ChannelEdgePolicy{ &models.ChannelEdgePolicy{
FeeBaseMSat: 1000, FeeBaseMSat: 1000,
FeeProportionalMillionths: 20, FeeProportionalMillionths: 20,
+15 -6
View File
@@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
graphdb "github.com/lightningnetwork/lnd/graph/db" graphdb "github.com/lightningnetwork/lnd/graph/db"
@@ -19,6 +20,7 @@ import (
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/netann"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -100,12 +102,19 @@ func createEdgePolicies(t *testing.T, channel *channeldb.OpenChannel,
// bit. // bit.
dir2 |= lnwire.ChanUpdateDirection dir2 |= lnwire.ChanUpdateDirection
return &models.ChannelEdgeInfo{ pubkey1Vertex, err := route.NewVertexFromBytes(pubkey1[:])
Version: lnwire.GossipVersion1, require.NoError(t, err)
ChannelPoint: channel.FundingOutpoint, pubkey2Vertex, err := route.NewVertexFromBytes(pubkey2[:])
NodeKey1Bytes: pubkey1, require.NoError(t, err)
NodeKey2Bytes: pubkey2,
}, edgeInfo, err := models.NewV1Channel(
channel.ShortChanID().ToUint64(), chainhash.Hash{},
pubkey1Vertex, pubkey2Vertex, &models.ChannelV1Fields{},
models.WithChannelPoint(channel.FundingOutpoint),
)
require.NoError(t, err)
return edgeInfo,
&models.ChannelEdgePolicy{ &models.ChannelEdgePolicy{
ChannelID: channel.ShortChanID().ToUint64(), ChannelID: channel.ShortChanID().ToUint64(),
ChannelFlags: dir1, ChannelFlags: dir1,
+13 -15
View File
@@ -46,21 +46,19 @@ func TestCreateChanAnnouncement(t *testing.T) {
expChanAnn.BitcoinSig1.ToSignatureBytes(), expChanAnn.BitcoinSig1.ToSignatureBytes(),
expChanAnn.BitcoinSig2.ToSignatureBytes(), expChanAnn.BitcoinSig2.ToSignatureBytes(),
) )
chanInfo := &models.ChannelEdgeInfo{ chanInfo, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, expChanAnn.ShortChannelID.ToUint64(), expChanAnn.ChainHash,
ChainHash: expChanAnn.ChainHash, key, key, &models.ChannelV1Fields{
ChannelID: expChanAnn.ShortChannelID.ToUint64(), BitcoinKey1Bytes: key,
ChannelPoint: wire.OutPoint{Index: 1}, BitcoinKey2Bytes: key,
Capacity: btcutil.SatoshiPerBitcoin, ExtraOpaqueData: expChanAnn.ExtraOpaqueData,
NodeKey1Bytes: key, },
NodeKey2Bytes: key, models.WithChanProof(chanProof),
BitcoinKey1Bytes: key, models.WithChannelPoint(wire.OutPoint{Index: 1}),
BitcoinKey2Bytes: key, models.WithCapacity(btcutil.SatoshiPerBitcoin),
Features: lnwire.NewFeatureVector( models.WithFeatures(features),
features, lnwire.Features, )
), require.NoError(t, err)
ExtraOpaqueData: expChanAnn.ExtraOpaqueData,
}
chanAnn, _, _, err := CreateChanAnnouncement( chanAnn, _, _, err := CreateChanAnnouncement(
chanProof, chanInfo, nil, nil, chanProof, chanInfo, nil, nil,
) )
+29 -12
View File
@@ -18,6 +18,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/routing/route"
) )
// Manager manages the node's local channels. The only operation that is // Manager manages the node's local channels. The only operation that is
@@ -328,20 +329,36 @@ func (r *Manager) createEdge(channel *channeldb.OpenChannel,
"script: %v", err) "script: %v", err)
} }
info := &models.ChannelEdgeInfo{ nodeKey1, err := route.NewVertexFromBytes(nodeKey1Bytes)
Version: lnwire.GossipVersion1, if err != nil {
ChannelID: shortChanID.ToUint64(), return nil, nil, err
ChainHash: channel.ChainHash, }
Features: lnwire.EmptyFeatureVector(), nodeKey2, err := route.NewVertexFromBytes(nodeKey2Bytes)
Capacity: channel.Capacity, if err != nil {
ChannelPoint: channel.FundingOutpoint, return nil, nil, err
FundingScript: fn.Some(fundingScript), }
bitcoinKey1, err := route.NewVertexFromBytes(bitcoinKey1Bytes)
if err != nil {
return nil, nil, err
}
bitcoinKey2, err := route.NewVertexFromBytes(bitcoinKey2Bytes)
if err != nil {
return nil, nil, err
} }
copy(info.NodeKey1Bytes[:], nodeKey1Bytes) info, err := models.NewV1Channel(
copy(info.NodeKey2Bytes[:], nodeKey2Bytes) shortChanID.ToUint64(), channel.ChainHash, nodeKey1, nodeKey2,
copy(info.BitcoinKey1Bytes[:], bitcoinKey1Bytes) &models.ChannelV1Fields{
copy(info.BitcoinKey2Bytes[:], bitcoinKey2Bytes) BitcoinKey1Bytes: bitcoinKey1,
BitcoinKey2Bytes: bitcoinKey2,
},
models.WithCapacity(channel.Capacity),
models.WithChannelPoint(channel.FundingOutpoint),
models.WithFundingScript(fundingScript),
)
if err != nil {
return nil, nil, err
}
// Construct a dummy channel edge policy with default values that will // Construct a dummy channel edge policy with default values that will
// be updated with the new values in the call to processChan below. // be updated with the new values in the call to processChan below.
+90 -55
View File
@@ -13,13 +13,13 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/fn/v2"
"github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/graph/db/models" "github.com/lightningnetwork/lnd/graph/db/models"
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -211,11 +211,21 @@ func TestManager(t *testing.T) {
newPolicy: newPolicy, newPolicy: newPolicy,
channelSet: []channel{ channelSet: []channel{
{ {
edgeInfo: &models.ChannelEdgeInfo{ //nolint:ll
Version: lnwire.GossipVersion1, edgeInfo: func() *models.ChannelEdgeInfo {
Capacity: chanCap, info, err := models.NewV1Channel(
ChannelPoint: chanPointValid, 0,
}, chainhash.Hash{},
route.Vertex{},
route.Vertex{},
&models.ChannelV1Fields{},
models.WithCapacity(chanCap),
models.WithChannelPoint(chanPointValid),
)
require.NoError(t, err)
return info
}(),
}, },
}, },
specifiedChanPoints: []wire.OutPoint{chanPointValid}, specifiedChanPoints: []wire.OutPoint{chanPointValid},
@@ -230,11 +240,21 @@ func TestManager(t *testing.T) {
newPolicy: newPolicy, newPolicy: newPolicy,
channelSet: []channel{ channelSet: []channel{
{ {
edgeInfo: &models.ChannelEdgeInfo{ //nolint:ll
Version: lnwire.GossipVersion1, edgeInfo: func() *models.ChannelEdgeInfo {
Capacity: chanCap, info, err := models.NewV1Channel(
ChannelPoint: chanPointValid, 0,
}, chainhash.Hash{},
route.Vertex{},
route.Vertex{},
&models.ChannelV1Fields{},
models.WithCapacity(chanCap),
models.WithChannelPoint(chanPointValid),
)
require.NoError(t, err)
return info
}(),
}, },
}, },
specifiedChanPoints: []wire.OutPoint{}, specifiedChanPoints: []wire.OutPoint{},
@@ -249,11 +269,22 @@ func TestManager(t *testing.T) {
newPolicy: newPolicy, newPolicy: newPolicy,
channelSet: []channel{ channelSet: []channel{
{ {
edgeInfo: &models.ChannelEdgeInfo{ //nolint:ll
Version: lnwire.GossipVersion1, edgeInfo: func() *models.ChannelEdgeInfo {
Capacity: chanCap, info, err := models.NewV1Channel(
ChannelPoint: chanPointValid, 0,
}, chainhash.Hash{},
route.Vertex{},
route.Vertex{},
&models.ChannelV1Fields{},
models.WithCapacity(chanCap),
models.WithChannelPoint(chanPointValid),
)
require.NoError(t, err)
return info
}(),
}, },
}, },
specifiedChanPoints: []wire.OutPoint{chanPointMissing}, specifiedChanPoints: []wire.OutPoint{chanPointMissing},
@@ -272,11 +303,22 @@ func TestManager(t *testing.T) {
newPolicy: noMaxHtlcPolicy, newPolicy: noMaxHtlcPolicy,
channelSet: []channel{ channelSet: []channel{
{ {
edgeInfo: &models.ChannelEdgeInfo{ //nolint:ll
Version: lnwire.GossipVersion1, edgeInfo: func() *models.ChannelEdgeInfo {
Capacity: chanCap, info, err := models.NewV1Channel(
ChannelPoint: chanPointValid, 0,
}, chainhash.Hash{},
route.Vertex{},
route.Vertex{},
&models.ChannelV1Fields{},
models.WithCapacity(chanCap),
models.WithChannelPoint(chanPointValid),
)
require.NoError(t, err)
return info
}(),
}, },
}, },
specifiedChanPoints: []wire.OutPoint{chanPointValid}, specifiedChanPoints: []wire.OutPoint{chanPointValid},
@@ -395,23 +437,19 @@ func TestCreateEdgeLower(t *testing.T) {
fundingScript, err := funding.MakeFundingScript(channel) fundingScript, err := funding.MakeFundingScript(channel)
require.NoError(t, err) require.NoError(t, err)
expectedInfo := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(localMultisigKey)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(remoteMultisigKey)
ChannelID: 8, expectedInfo, err := models.NewV1Channel(
ChainHash: channel.ChainHash, 8, channel.ChainHash, sp, rp, &models.ChannelV1Fields{
Features: lnwire.EmptyFeatureVector(), BitcoinKey1Bytes: btcKey1,
Capacity: 9, BitcoinKey2Bytes: btcKey2,
ChannelPoint: channel.FundingOutpoint, },
NodeKey1Bytes: sp, models.WithCapacity(9),
NodeKey2Bytes: rp, models.WithChannelPoint(channel.FundingOutpoint),
BitcoinKey1Bytes: [33]byte( models.WithFundingScript(fundingScript),
localMultisigKey.SerializeCompressed()), )
BitcoinKey2Bytes: [33]byte( require.NoError(t, err)
remoteMultisigKey.SerializeCompressed()),
AuthProof: nil,
ExtraOpaqueData: nil,
FundingScript: fn.Some(fundingScript),
}
expectedEdge := &models.ChannelEdgePolicy{ expectedEdge := &models.ChannelEdgePolicy{
ChannelID: 8, ChannelID: 8,
LastUpdate: timestamp, LastUpdate: timestamp,
@@ -489,23 +527,20 @@ func TestCreateEdgeHigher(t *testing.T) {
fundingScript, err := funding.MakeFundingScript(channel) fundingScript, err := funding.MakeFundingScript(channel)
require.NoError(t, err) require.NoError(t, err)
expectedInfo := &models.ChannelEdgeInfo{ btcKey1 := route.NewVertex(remoteMultisigKey)
Version: lnwire.GossipVersion1, btcKey2 := route.NewVertex(localMultisigKey)
ChannelID: 8, expectedInfo, err := models.NewV1Channel(
ChainHash: channel.ChainHash, 8, channel.ChainHash, rp, sp,
Features: lnwire.EmptyFeatureVector(), &models.ChannelV1Fields{
Capacity: 9, BitcoinKey1Bytes: btcKey1,
ChannelPoint: channel.FundingOutpoint, BitcoinKey2Bytes: btcKey2,
NodeKey1Bytes: rp, },
NodeKey2Bytes: sp, models.WithCapacity(9),
BitcoinKey1Bytes: [33]byte( models.WithChannelPoint(channel.FundingOutpoint),
remoteMultisigKey.SerializeCompressed()), models.WithFundingScript(fundingScript),
BitcoinKey2Bytes: [33]byte( )
localMultisigKey.SerializeCompressed()), require.NoError(t, err)
AuthProof: nil,
ExtraOpaqueData: nil,
FundingScript: fn.Some(fundingScript),
}
expectedEdge := &models.ChannelEdgePolicy{ expectedEdge := &models.ChannelEdgePolicy{
ChannelID: 8, ChannelID: 8,
LastUpdate: timestamp, LastUpdate: timestamp,
+38 -28
View File
@@ -19,6 +19,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
sphinx "github.com/lightningnetwork/lightning-onion" sphinx "github.com/lightningnetwork/lightning-onion"
@@ -345,19 +346,28 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
// We first insert the existence of the edge between the two // We first insert the existence of the edge between the two
// nodes. // nodes.
edgeInfo := models.ChannelEdgeInfo{ var node1Vertex, node2Vertex route.Vertex
Version: lnwire.GossipVersion1, copy(node1Vertex[:], node1Bytes)
ChannelID: edge.ChannelID, copy(node2Vertex[:], node2Bytes)
AuthProof: &testAuthProof,
ChannelPoint: fundingPoint,
Features: lnwire.EmptyFeatureVector(),
Capacity: btcutil.Amount(edge.Capacity),
}
copy(edgeInfo.NodeKey1Bytes[:], node1Bytes) var btcKey1, btcKey2 route.Vertex
copy(edgeInfo.NodeKey2Bytes[:], node2Bytes) copy(btcKey1[:], node1Bytes)
copy(edgeInfo.BitcoinKey1Bytes[:], node1Bytes) copy(btcKey2[:], node2Bytes)
copy(edgeInfo.BitcoinKey2Bytes[:], node2Bytes)
edgeInfo, err := models.NewV1Channel(
edge.ChannelID, *chaincfg.SimNetParams.GenesisHash,
node1Vertex, node2Vertex,
&models.ChannelV1Fields{
BitcoinKey1Bytes: btcKey1,
BitcoinKey2Bytes: btcKey2,
},
models.WithChanProof(&testAuthProof),
models.WithChannelPoint(fundingPoint),
models.WithCapacity(btcutil.Amount(edge.Capacity)),
)
if err != nil {
return nil, err
}
shortID := lnwire.NewShortChanIDFromInt(edge.ChannelID) shortID := lnwire.NewShortChanIDFromInt(edge.ChannelID)
links[shortID] = &mockLink{ links[shortID] = &mockLink{
@@ -366,7 +376,7 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
), ),
} }
err = graph.AddChannelEdge(ctx, &edgeInfo) err = graph.AddChannelEdge(ctx, edgeInfo)
if err != nil && !errors.Is(err, graphdb.ErrEdgeAlreadyExist) { if err != nil && !errors.Is(err, graphdb.ErrEdgeAlreadyExist) {
return nil, err return nil, err
} }
@@ -396,12 +406,12 @@ func parseTestGraph(t *testing.T, useCache bool, path string) (
} }
// We also store the channel IDs info for each of the node. // We also store the channel IDs info for each of the node.
node1Vertex, err := route.NewVertexFromBytes(node1Bytes) node1Vertex, err = route.NewVertexFromBytes(node1Bytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
node2Vertex, err := route.NewVertexFromBytes(node2Bytes) node2Vertex, err = route.NewVertexFromBytes(node2Bytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -678,21 +688,21 @@ func createTestGraphFromChannels(t *testing.T, useCache bool,
// We first insert the existence of the edge between the two // We first insert the existence of the edge between the two
// nodes. // nodes.
edgeInfo := models.ChannelEdgeInfo{ edgeInfo, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, channelID, *chaincfg.SimNetParams.GenesisHash,
ChannelID: channelID, node1Vertex, node2Vertex, &models.ChannelV1Fields{
AuthProof: &testAuthProof, BitcoinKey1Bytes: node1Vertex,
ChannelPoint: *fundingPoint, BitcoinKey2Bytes: node2Vertex,
Capacity: testChannel.Capacity, },
Features: lnwire.EmptyFeatureVector(), models.WithChanProof(&testAuthProof),
models.WithChannelPoint(*fundingPoint),
NodeKey1Bytes: node1Vertex, models.WithCapacity(testChannel.Capacity),
BitcoinKey1Bytes: node1Vertex, )
NodeKey2Bytes: node2Vertex, if err != nil {
BitcoinKey2Bytes: node2Vertex, return nil, err
} }
err = graph.AddChannelEdge(ctx, &edgeInfo) err = graph.AddChannelEdge(ctx, edgeInfo)
if err != nil && !errors.Is(err, graphdb.ErrEdgeAlreadyExist) { if err != nil && !errors.Is(err, graphdb.ErrEdgeAlreadyExist) {
return nil, err return nil, err
} }
+19 -20
View File
@@ -2738,16 +2738,14 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
) )
require.NoError(t, err, "unable to create channel edge") require.NoError(t, err, "unable to create channel edge")
edge := &models.ChannelEdgeInfo{ edge, err := models.NewV1Channel(
Version: lnwire.GossipVersion1, chanID.ToUint64(), chainhash.Hash{}, pub1, pub2,
ChannelID: chanID.ToUint64(), &models.ChannelV1Fields{
NodeKey1Bytes: pub1, BitcoinKey1Bytes: pub1,
NodeKey2Bytes: pub2, BitcoinKey2Bytes: pub2,
BitcoinKey1Bytes: pub1, },
BitcoinKey2Bytes: pub2, )
Features: lnwire.EmptyFeatureVector(), require.NoError(t, err)
AuthProof: nil,
}
require.NoError(t, ctx.graph.AddChannelEdge(ctxb, edge)) require.NoError(t, ctx.graph.AddChannelEdge(ctxb, edge))
// We must add the edge policy to be able to use the edge for route // We must add the edge policy to be able to use the edge for route
@@ -2819,16 +2817,17 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
10000, 510) 10000, 510)
require.NoError(t, err, "unable to create channel edge") require.NoError(t, err, "unable to create channel edge")
edge = &models.ChannelEdgeInfo{ node1Vertex, err := route.NewVertexFromBytes(node1Bytes)
Version: lnwire.GossipVersion1, require.NoError(t, err)
ChannelID: chanID.ToUint64(),
Features: lnwire.EmptyFeatureVector(), edge, err = models.NewV1Channel(
AuthProof: nil, chanID.ToUint64(), chainhash.Hash{}, node1Vertex, node2Bytes,
} &models.ChannelV1Fields{
copy(edge.NodeKey1Bytes[:], node1Bytes) BitcoinKey1Bytes: node1Vertex,
edge.NodeKey2Bytes = node2Bytes BitcoinKey2Bytes: node2Bytes,
copy(edge.BitcoinKey1Bytes[:], node1Bytes) },
edge.BitcoinKey2Bytes = node2Bytes )
require.NoError(t, err)
require.NoError(t, ctx.graph.AddChannelEdge(ctxb, edge)) require.NoError(t, ctx.graph.AddChannelEdge(ctxb, edge))