graph/db: support v2 channel proofs in AddEdgeProof

Update AddEdgeProof to handle both v1 (four separate signatures) and
v2 (single aggregated signature) channel authentication proofs using
the appropriate SQL queries.
This commit is contained in:
Elle Mouton committed 2026-02-13 07:21:23 +02:00
1 parent 315f5ed741
commit 99d622ca03
2 files changed
+92 -87

No files matched your search

+62 -76
View File
@@ -138,6 +138,10 @@ var versionedTests = []versionedTest{
name: "alias lookup", name: "alias lookup",
test: testAliasLookup, test: testAliasLookup,
}, },
{
name: "add edge proof",
test: testAddEdgeProof,
},
} }
// TestVersionedDBs runs various tests against both v1 and v2 versioned // TestVersionedDBs runs various tests against both v1 and v2 versioned
@@ -644,8 +648,10 @@ func TestEdgeInsertionDeletion(t *testing.T) {
} }
func createEdge(version lnwire.GossipVersion, height, txIndex uint32, func createEdge(version lnwire.GossipVersion, height, txIndex uint32,
txPosition uint16, outPointIndex uint32, node1, node2 *models.Node) ( txPosition uint16, outPointIndex uint32, node1, node2 *models.Node,
*models.ChannelEdgeInfo, lnwire.ShortChannelID) { skipProof ...bool) (*models.ChannelEdgeInfo, lnwire.ShortChannelID) {
shouldSkipProof := len(skipProof) > 0 && skipProof[0]
shortChanID := lnwire.ShortChannelID{ shortChanID := lnwire.ShortChannelID{
BlockHeight: height, BlockHeight: height,
@@ -677,12 +683,19 @@ func createEdge(version lnwire.GossipVersion, height, txIndex uint32,
node2Pub.SerializeCompressed(), node2Pub.SerializeCompressed(),
) )
proof := models.NewV1ChannelAuthProof( opts := []models.EdgeModifier{
testSig.Serialize(), models.WithChannelPoint(outpoint),
testSig.Serialize(), models.WithCapacity(9000),
testSig.Serialize(), }
testSig.Serialize(), if !shouldSkipProof {
) proof := models.NewV1ChannelAuthProof(
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
)
opts = append(opts, models.WithChanProof(proof))
}
edgeInfo, _ = models.NewV1Channel( edgeInfo, _ = models.NewV1Channel(
shortChanID.ToUint64(), shortChanID.ToUint64(),
@@ -694,9 +707,7 @@ func createEdge(version lnwire.GossipVersion, height, txIndex uint32,
BitcoinKey2Bytes: btcKey2, BitcoinKey2Bytes: btcKey2,
ExtraOpaqueData: make([]byte, 0), ExtraOpaqueData: make([]byte, 0),
}, },
models.WithChanProof(proof), opts...,
models.WithChannelPoint(outpoint),
models.WithCapacity(9000),
) )
case lnwire.GossipVersion2: case lnwire.GossipVersion2:
@@ -717,7 +728,16 @@ func createEdge(version lnwire.GossipVersion, height, txIndex uint32,
fundingScript, bytes.Repeat([]byte{0xbb}, 32)..., fundingScript, bytes.Repeat([]byte{0xbb}, 32)...,
) )
proof := models.NewV2ChannelAuthProof(testSig.Serialize()) opts := []models.EdgeModifier{
models.WithChannelPoint(outpoint),
models.WithCapacity(9000),
}
if !shouldSkipProof {
proof := models.NewV2ChannelAuthProof(
testSig.Serialize(),
)
opts = append(opts, models.WithChanProof(proof))
}
edgeInfo, _ = models.NewV2Channel( edgeInfo, _ = models.NewV2Channel(
shortChanID.ToUint64(), shortChanID.ToUint64(),
@@ -731,9 +751,7 @@ func createEdge(version lnwire.GossipVersion, height, txIndex uint32,
FundingScript: fn.Some(fundingScript), FundingScript: fn.Some(fundingScript),
ExtraSignedFields: make(map[uint64][]byte), ExtraSignedFields: make(map[uint64][]byte),
}, },
models.WithChanProof(proof), opts...,
models.WithChannelPoint(outpoint),
models.WithCapacity(9000),
) )
} }
@@ -940,29 +958,9 @@ func assertEdgeInfoEqual(t *testing.T, e1 *models.ChannelEdgeInfo,
} }
} }
type createEdgeConfig struct { func createChannelEdge(node1, node2 *models.Node) (*models.ChannelEdgeInfo,
skipProofs bool
}
type createEdgeOpt func(*createEdgeConfig)
// withSkipProofs will let createChannelEdge create an edge without auth
// proofs. In this case, createChannelEdge will then also not create policies.
func withSkipProofs() createEdgeOpt {
return func(cfg *createEdgeConfig) {
cfg.skipProofs = true
}
}
func createChannelEdge(node1, node2 *models.Node,
options ...createEdgeOpt) (*models.ChannelEdgeInfo,
*models.ChannelEdgePolicy, *models.ChannelEdgePolicy) { *models.ChannelEdgePolicy, *models.ChannelEdgePolicy) {
var opts createEdgeConfig
for _, o := range options {
o(&opts)
}
var ( var (
firstNode [33]byte firstNode [33]byte
secondNode [33]byte secondNode [33]byte
@@ -995,21 +993,6 @@ func createChannelEdge(node1, node2 *models.Node,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
} }
var edgeInfo *models.ChannelEdgeInfo
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
}
proof := models.NewV1ChannelAuthProof( proof := models.NewV1ChannelAuthProof(
testSig.Serialize(), testSig.Serialize(),
testSig.Serialize(), testSig.Serialize(),
@@ -1017,7 +1000,7 @@ func createChannelEdge(node1, node2 *models.Node,
testSig.Serialize(), testSig.Serialize(),
) )
edgeInfo, _ = models.NewV1Channel( edgeInfo, _ := models.NewV1Channel(
chanID, *chaincfg.MainNetParams.GenesisHash, node1Key, node2Key, chanID, *chaincfg.MainNetParams.GenesisHash, node1Key, node2Key,
&models.ChannelV1Fields{ &models.ChannelV1Fields{
BitcoinKey1Bytes: node1Key, BitcoinKey1Bytes: node1Key,
@@ -1457,42 +1440,48 @@ func newEdgePolicy(chanID uint64, updateTime int64) *models.ChannelEdgePolicy {
} }
} }
// TestAddEdgeProof tests the ability to add an edge proof to an existing edge. // testAddEdgeProof tests the ability to add an edge proof to an existing edge.
func TestAddEdgeProof(t *testing.T) { func testAddEdgeProof(t *testing.T, v lnwire.GossipVersion) {
t.Parallel() t.Parallel()
ctx := t.Context() ctx := t.Context()
graph := MakeTestGraph(t) graph := NewVersionedGraph(MakeTestGraph(t), v)
// Add an edge with no proof. // Add an edge with no proof.
node1 := createTestVertex(t, lnwire.GossipVersion1) node1 := createTestVertex(t, v)
node2 := createTestVertex(t, lnwire.GossipVersion1) node2 := createTestVertex(t, v)
edge1, _, _ := createChannelEdge(node1, node2, withSkipProofs())
// Create edge without proof (skipProof = true).
edge1, _ := createEdge(v, 100, 0, 0, 0, node1, node2, true)
require.NoError(t, graph.AddChannelEdge(ctx, edge1)) require.NoError(t, graph.AddChannelEdge(ctx, edge1))
// Fetch the edge and assert that the proof is nil and that the rest // Fetch the edge and assert that the proof is nil.
// of the edge info is correct.
dbEdge, _, _, err := graph.FetchChannelEdgesByID(edge1.ChannelID) dbEdge, _, _, err := graph.FetchChannelEdgesByID(edge1.ChannelID)
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, dbEdge.AuthProof) require.Nil(t, dbEdge.AuthProof)
require.Equal(t, edge1, dbEdge)
// Now, add the edge proof. // Create a proof appropriate for the version.
proof := models.NewV1ChannelAuthProof( var proof *models.ChannelAuthProof
testSig.Serialize(), switch v {
testSig.Serialize(), case lnwire.GossipVersion1:
testSig.Serialize(), proof = models.NewV1ChannelAuthProof(
testSig.Serialize(), testSig.Serialize(),
) testSig.Serialize(),
testSig.Serialize(),
testSig.Serialize(),
)
case lnwire.GossipVersion2:
proof = models.NewV2ChannelAuthProof(testSig.Serialize())
}
// First, add the proof to the rest of the channel edge info and try // First, add the proof to the rest of the channel edge info and try
// to call AddChannelEdge again - this should fail due to the channel // to call AddChannelEdge again - this should fail due to the channel
// already existing. // already existing.
edge1.AuthProof = proof edge1.AuthProof = proof
err = graph.AddChannelEdge(ctx, edge1) err = graph.AddChannelEdge(ctx, edge1)
require.Error(t, err, ErrEdgeAlreadyExist) require.ErrorIs(t, err, ErrEdgeAlreadyExist)
// Now add just the proof. // Now add just the proof via AddEdgeProof.
scid1 := lnwire.NewShortChanIDFromInt(edge1.ChannelID) scid1 := lnwire.NewShortChanIDFromInt(edge1.ChannelID)
require.NoError(t, graph.AddEdgeProof(scid1, proof)) require.NoError(t, graph.AddEdgeProof(scid1, proof))
@@ -1500,19 +1489,16 @@ func TestAddEdgeProof(t *testing.T) {
dbEdge, _, _, err = graph.FetchChannelEdgesByID(edge1.ChannelID) dbEdge, _, _, err = graph.FetchChannelEdgesByID(edge1.ChannelID)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, dbEdge.AuthProof) require.NotNil(t, dbEdge.AuthProof)
require.Equal(t, edge1, dbEdge)
// For completeness, also test the case where we insert a new edge with // For completeness, also test the case where we insert a new edge with
// an edge proof. Show that the proof is present from the get go. // an edge proof from the start. Show that the proof is present.
edge2, _, _ := createChannelEdge(node1, node2) edge2, _ := createEdge(v, 200, 0, 0, 1, node1, node2)
require.NoError(t, graph.AddChannelEdge(ctx, edge2)) require.NoError(t, graph.AddChannelEdge(ctx, edge2))
// Fetch the edge and assert that the proof is nil and that the rest // Fetch the edge and assert that the proof is set.
// of the edge info is correct.
dbEdge2, _, _, err := graph.FetchChannelEdgesByID(edge2.ChannelID) dbEdge2, _, _, err := graph.FetchChannelEdgesByID(edge2.ChannelID)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, dbEdge2.AuthProof) require.NotNil(t, dbEdge2.AuthProof)
require.Equal(t, edge2, dbEdge2)
} }
// TestForEachSourceNodeChannel tests that the ForEachSourceNodeChannel // TestForEachSourceNodeChannel tests that the ForEachSourceNodeChannel
+30 -11
View File
@@ -82,6 +82,7 @@ type SQLQueries interface {
*/ */
CreateChannel(ctx context.Context, arg sqlc.CreateChannelParams) (int64, error) CreateChannel(ctx context.Context, arg sqlc.CreateChannelParams) (int64, error)
AddV1ChannelProof(ctx context.Context, arg sqlc.AddV1ChannelProofParams) (sql.Result, error) AddV1ChannelProof(ctx context.Context, arg sqlc.AddV1ChannelProofParams) (sql.Result, error)
AddV2ChannelProof(ctx context.Context, arg sqlc.AddV2ChannelProofParams) (sql.Result, error)
GetChannelBySCID(ctx context.Context, arg sqlc.GetChannelBySCIDParams) (sqlc.GraphChannel, error) GetChannelBySCID(ctx context.Context, arg sqlc.GetChannelBySCIDParams) (sqlc.GraphChannel, error)
GetChannelsBySCIDs(ctx context.Context, arg sqlc.GetChannelsBySCIDsParams) ([]sqlc.GraphChannel, error) GetChannelsBySCIDs(ctx context.Context, arg sqlc.GetChannelsBySCIDsParams) ([]sqlc.GraphChannel, error)
GetChannelsByOutpoints(ctx context.Context, outpoints []string) ([]sqlc.GetChannelsByOutpointsRow, error) GetChannelsByOutpoints(ctx context.Context, outpoints []string) ([]sqlc.GetChannelsByOutpointsRow, error)
@@ -2984,9 +2985,8 @@ func (s *SQLStore) DisconnectBlockAtHeight(height uint32) (
func (s *SQLStore) AddEdgeProof(scid lnwire.ShortChannelID, func (s *SQLStore) AddEdgeProof(scid lnwire.ShortChannelID,
proof *models.ChannelAuthProof) error { proof *models.ChannelAuthProof) error {
// For now, we only support v1 channel proofs. if !isKnownGossipVersion(proof.Version) {
if proof.Version != lnwire.GossipVersion1 { return fmt.Errorf("unsupported gossip version: %d",
return fmt.Errorf("only v1 channel proofs supported, got v%d",
proof.Version) proof.Version)
} }
@@ -2996,15 +2996,34 @@ func (s *SQLStore) AddEdgeProof(scid lnwire.ShortChannelID,
) )
err := s.db.ExecTx(ctx, sqldb.WriteTxOpt(), func(db SQLQueries) error { err := s.db.ExecTx(ctx, sqldb.WriteTxOpt(), func(db SQLQueries) error {
res, err := db.AddV1ChannelProof( var (
ctx, sqlc.AddV1ChannelProofParams{ res sql.Result
Scid: scidBytes, err error
Node1Signature: proof.NodeSig1(),
Node2Signature: proof.NodeSig2(),
Bitcoin1Signature: proof.BitcoinSig1(),
Bitcoin2Signature: proof.BitcoinSig2(),
},
) )
switch proof.Version {
case lnwire.GossipVersion1:
res, err = db.AddV1ChannelProof(
ctx, sqlc.AddV1ChannelProofParams{
Scid: scidBytes,
Node1Signature: proof.NodeSig1(),
Node2Signature: proof.NodeSig2(),
Bitcoin1Signature: proof.BitcoinSig1(),
Bitcoin2Signature: proof.BitcoinSig2(),
},
)
case lnwire.GossipVersion2:
res, err = db.AddV2ChannelProof(
ctx, sqlc.AddV2ChannelProofParams{
Scid: scidBytes,
Signature: proof.Sig(),
},
)
default:
return fmt.Errorf("unsupported gossip version: %d",
proof.Version)
}
if err != nil { if err != nil {
return fmt.Errorf("unable to add edge proof: %w", err) return fmt.Errorf("unable to add edge proof: %w", err)
} }