Skip to content

Commit 7cdf976

Browse files
authored
Merge pull request #10716 from ellemouton/g175-graph-db-v2-test-conversion
graph/db: convert v1-only tests to versioned v1+v2 tests
2 parents 9bf4f50 + a390ddd commit 7cdf976

1 file changed

Lines changed: 127 additions & 87 deletions

File tree

graph/db/graph_test.go

Lines changed: 127 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/btcsuite/btcd/btcec/v2"
1919
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
20+
"github.com/btcsuite/btcd/btcec/v2/schnorr"
2021
"github.com/btcsuite/btcd/btcutil"
2122
"github.com/btcsuite/btcd/chaincfg"
2223
"github.com/btcsuite/btcd/chaincfg/chainhash"
@@ -214,6 +215,22 @@ var versionedTests = []versionedTest{
214215
name: "channel view taproot v1 round trip",
215216
test: testChannelViewTaprootV1RoundTrip,
216217
},
218+
{
219+
name: "node pruning update index deletion",
220+
test: testNodePruningUpdateIndexDeletion,
221+
},
222+
{
223+
name: "lightning node sig verification",
224+
test: testLightningNodeSigVerification,
225+
},
226+
{
227+
name: "graph zombie index",
228+
test: testGraphZombieIndex,
229+
},
230+
{
231+
name: "disconnect block at height",
232+
test: testDisconnectBlockAtHeight,
233+
},
217234
}
218235

219236
// TestVersionedDBs runs various tests against both v1 and v2 versioned
@@ -853,21 +870,21 @@ func createEdge(version lnwire.GossipVersion, height, txIndex uint32,
853870
return edgeInfo, shortChanID
854871
}
855872

856-
// TestDisconnectBlockAtHeight checks that the pruned state of the channel
873+
// testDisconnectBlockAtHeight checks that the pruned state of the channel
857874
// database is what we expect after calling DisconnectBlockAtHeight.
858-
func TestDisconnectBlockAtHeight(t *testing.T) {
875+
func testDisconnectBlockAtHeight(t *testing.T, v lnwire.GossipVersion) {
859876
t.Parallel()
860877
ctx := t.Context()
861878

862879
graph := MakeTestGraph(t, WithSyncGraphCachePopulation())
863880

864-
sourceNode := createTestVertex(t, lnwire.GossipVersion1)
881+
sourceNode := createTestVertex(t, v)
865882
require.NoError(t, graph.SetSourceNode(ctx, sourceNode))
866883

867884
// We'd like to test the insertion/deletion of edges, so we create two
868885
// vertexes to connect.
869-
node1 := createTestVertex(t, lnwire.GossipVersion1)
870-
node2 := createTestVertex(t, lnwire.GossipVersion1)
886+
node1 := createTestVertex(t, v)
887+
node2 := createTestVertex(t, v)
871888

872889
// In addition to the fake vertexes we create some fake channel
873890
// identifiers.
@@ -885,29 +902,20 @@ func TestDisconnectBlockAtHeight(t *testing.T) {
885902
_, err = graph.PruneGraph(ctx, spendOutputs, &blockHash2, 156)
886903
require.NoError(t, err, "unable to prune graph")
887904

888-
// We'll create 3 almost identical edges, so first create a helper
889-
// method containing all logic for doing so.
890-
891905
// Create an edge which has its block height at 156.
892906
height := uint32(156)
893-
edgeInfo, _ := createEdge(
894-
lnwire.GossipVersion1, height, 0, 0, 0, node1, node2,
895-
)
907+
edgeInfo, _ := createEdge(v, height, 0, 0, 0, node1, node2)
896908

897-
// Create an edge with block height 157. We give it
898-
// maximum values for tx index and position, to make
899-
// sure our database range scan get edges from the
900-
// entire range.
909+
// Create an edge with block height 157. We give it maximum values for
910+
// tx index and position, to make sure our database range scan gets
911+
// edges from the entire range.
901912
edgeInfo2, _ := createEdge(
902-
lnwire.GossipVersion1, height+1,
903-
math.MaxUint32&0x00ffffff, math.MaxUint16, 1, node1,
904-
node2,
913+
v, height+1, math.MaxUint32&0x00ffffff, math.MaxUint16,
914+
1, node1, node2,
905915
)
906916

907917
// Create a third edge, this with a block height of 155.
908-
edgeInfo3, _ := createEdge(
909-
lnwire.GossipVersion1, height-1, 0, 0, 2, node1, node2,
910-
)
918+
edgeInfo3, _ := createEdge(v, height-1, 0, 0, 2, node1, node2)
911919

912920
// Now add all these new edges to the database.
913921
require.NoError(t, graph.AddChannelEdge(ctx, edgeInfo))
@@ -932,21 +940,21 @@ func TestDisconnectBlockAtHeight(t *testing.T) {
932940

933941
// The two first edges should be removed from the db.
934942
has, isZombie, err := graph.HasChannelEdge(
935-
ctx, lnwire.GossipVersion1, edgeInfo.ChannelID,
943+
ctx, v, edgeInfo.ChannelID,
936944
)
937945
require.NoError(t, err, "unable to query for edge")
938946
require.False(t, has)
939947
require.False(t, isZombie)
940948
has, isZombie, err = graph.HasChannelEdge(
941-
ctx, lnwire.GossipVersion1, edgeInfo2.ChannelID,
949+
ctx, v, edgeInfo2.ChannelID,
942950
)
943951
require.NoError(t, err, "unable to query for edge")
944952
require.False(t, has)
945953
require.False(t, isZombie)
946954

947955
// Edge 3 should not be removed.
948956
has, isZombie, err = graph.HasChannelEdge(
949-
ctx, lnwire.GossipVersion1, edgeInfo3.ChannelID,
957+
ctx, v, edgeInfo3.ChannelID,
950958
)
951959
require.NoError(t, err, "unable to query for edge")
952960
require.True(t, has)
@@ -4395,14 +4403,18 @@ func TestFilterChannelRangeVersionGuard(t *testing.T) {
43954403

43964404
store := NewTestDB(t)
43974405

4398-
_, err := store.FilterChannelRange(
4406+
resp, err := store.FilterChannelRange(
43994407
ctx, lnwire.GossipVersion2, 0, 1000, false,
44004408
)
44014409

4402-
// The KV store does not support v2 and must return the sentinel error.
4403-
// The SQL store accepts any known version (returning empty results
4404-
// since no v2 channels have been added).
4405-
if err != nil {
4410+
if isSQLDB {
4411+
// The SQL store accepts any known version and returns empty
4412+
// results since no v2 channels have been added.
4413+
require.NoError(t, err)
4414+
require.Empty(t, resp)
4415+
} else {
4416+
// The KV store does not support v2 and must return the
4417+
// sentinel error.
44064418
require.ErrorIs(t, err, ErrVersionNotSupportedForKVDB)
44074419
}
44084420
}
@@ -4915,27 +4927,45 @@ func testAddChannelEdgeShellNodes(t *testing.T, v lnwire.GossipVersion) {
49154927
// TestNodePruningUpdateIndexDeletion tests that once a node has been removed
49164928
// from the channel graph, we also remove the entry from the update index as
49174929
// well.
4918-
func TestNodePruningUpdateIndexDeletion(t *testing.T) {
4930+
// testNodePruningUpdateIndexDeletion verifies that deleting a node also removes
4931+
// it from the update index used by NodeUpdatesInHorizon.
4932+
func testNodePruningUpdateIndexDeletion(t *testing.T,
4933+
v lnwire.GossipVersion) {
4934+
49194935
t.Parallel()
49204936
ctx := t.Context()
49214937

4922-
graph := NewVersionedGraph(MakeTestGraph(t), lnwire.GossipVersion1)
4938+
graph := NewVersionedGraph(MakeTestGraph(t), v)
49234939

49244940
// We'll first populate our graph with a single node that will be
49254941
// removed shortly.
4926-
node1 := createTestVertex(t, lnwire.GossipVersion1)
4942+
node1 := createTestVertex(t, v)
49274943
require.NoError(t, graph.AddNode(ctx, node1))
49284944

4945+
// Build a NodeUpdateRange that covers the node we just inserted. V1
4946+
// uses time-based ranges, v2 uses block-height-based ranges.
4947+
var updateRange NodeUpdateRange
4948+
switch v {
4949+
case lnwire.GossipVersion1:
4950+
updateRange = NodeUpdateRange{
4951+
StartTime: fn.Some(time.Unix(9, 0)),
4952+
EndTime: fn.Some(
4953+
node1.LastUpdate.Add(time.Minute),
4954+
),
4955+
}
4956+
case lnwire.GossipVersion2:
4957+
updateRange = NodeUpdateRange{
4958+
StartHeight: fn.Some(uint32(0)),
4959+
EndHeight: fn.Some(
4960+
node1.LastBlockHeight + 1,
4961+
),
4962+
}
4963+
}
4964+
49294965
// We'll confirm that we can retrieve the node using
4930-
// NodeUpdatesInHorizon, using a time that's slightly beyond the last
4931-
// update time of our test node.
4932-
startTime := time.Unix(9, 0)
4933-
endTime := node1.LastUpdate.Add(time.Minute)
4966+
// NodeUpdatesInHorizon.
49344967
nodesInHorizonIter := graph.NodeUpdatesInHorizon(
4935-
ctx, NodeUpdateRange{
4936-
StartTime: fn.Some(startTime),
4937-
EndTime: fn.Some(endTime),
4938-
},
4968+
ctx, updateRange,
49394969
)
49404970

49414971
// We should only have a single node, and that node should exactly
@@ -4953,10 +4983,7 @@ func TestNodePruningUpdateIndexDeletion(t *testing.T) {
49534983
// Now that the node has been deleted, we'll again query the nodes in
49544984
// the horizon. This time we should have no nodes at all.
49554985
nodesInHorizonIter = graph.NodeUpdatesInHorizon(
4956-
ctx, NodeUpdateRange{
4957-
StartTime: fn.Some(startTime),
4958-
EndTime: fn.Some(endTime),
4959-
},
4986+
ctx, updateRange,
49604987
)
49614988
nodesInHorizon, err = fn.CollectErr(nodesInHorizonIter)
49624989
require.NoError(t, err, "unable to fetch nodes in horizon")
@@ -5373,95 +5400,91 @@ func putSerializedPolicy(t *testing.T, db kvdb.Backend, from []byte,
53735400
require.NoError(t, err, "error writing db")
53745401
}
53755402

5376-
// assertNumZombies queries the provided ChannelGraph for NumZombies, and
5377-
// asserts that the returned number is equal to expZombies.
5378-
func assertNumZombies(t *testing.T, graph *ChannelGraph, expZombies uint64) {
5403+
// assertNumZombies queries the provided ChannelGraph for NumZombies for the
5404+
// given gossip version and asserts that the result equals the expected count.
5405+
func assertNumZombies(t *testing.T, graph *ChannelGraph,
5406+
v lnwire.GossipVersion, expZombies uint64) {
5407+
53795408
t.Helper()
53805409

5381-
v1Graph := NewVersionedGraph(graph, lnwire.GossipVersion1)
5382-
numZombies, err := v1Graph.NumZombies(t.Context())
5410+
vGraph := NewVersionedGraph(graph, v)
5411+
numZombies, err := vGraph.NumZombies(t.Context())
53835412
require.NoError(t, err, "unable to query number of zombies")
53845413
require.Equal(t, expZombies, numZombies)
53855414
}
53865415

5387-
// TestGraphZombieIndex ensures that we can mark edges correctly as zombie/live.
5388-
func TestGraphZombieIndex(t *testing.T) {
5416+
// testGraphZombieIndex ensures that we can mark edges correctly as zombie/live.
5417+
func testGraphZombieIndex(t *testing.T, v lnwire.GossipVersion) {
53895418
t.Parallel()
53905419
ctx := t.Context()
53915420

53925421
// We'll start by creating our test graph along with a test edge.
53935422
graph := MakeTestGraph(t)
53945423

5395-
node1 := createTestVertex(t, lnwire.GossipVersion1)
5396-
node2 := createTestVertex(t, lnwire.GossipVersion1)
5424+
node1 := createTestVertex(t, v)
5425+
node2 := createTestVertex(t, v)
53975426

53985427
// Swap the nodes if the second's pubkey is smaller than the first.
53995428
// Without this, the comparisons at the end will fail probabilistically.
54005429
if bytes.Compare(node2.PubKeyBytes[:], node1.PubKeyBytes[:]) < 0 {
54015430
node1, node2 = node2, node1
54025431
}
54035432

5404-
edge, _, _ := createChannelEdge(
5405-
node1, node2, lnwire.GossipVersion1,
5406-
)
5433+
edge, _, _ := createChannelEdge(node1, node2, v)
54075434
require.NoError(t, graph.AddChannelEdge(ctx, edge))
54085435

5409-
v1Graph := NewVersionedGraph(graph, lnwire.GossipVersion1)
5436+
vGraph := NewVersionedGraph(graph, v)
54105437

54115438
// Since the edge is known the graph and it isn't a zombie, IsZombieEdge
54125439
// should not report the channel as a zombie.
5413-
isZombie, _, _, err := v1Graph.IsZombieEdge(ctx, edge.ChannelID)
5440+
isZombie, _, _, err := vGraph.IsZombieEdge(ctx, edge.ChannelID)
54145441
require.NoError(t, err)
54155442
require.False(t, isZombie)
5416-
assertNumZombies(t, graph, 0)
5443+
assertNumZombies(t, graph, v, 0)
54175444

54185445
// If we delete the edge and mark it as a zombie, then we should expect
54195446
// to see it within the index.
5420-
err = graph.DeleteChannelEdges(
5421-
ctx, lnwire.GossipVersion1, false, true, edge.ChannelID,
5422-
)
5447+
err = graph.DeleteChannelEdges(ctx, v, false, true, edge.ChannelID)
54235448
require.NoError(t, err, "unable to mark edge as zombie")
5424-
isZombie, pubKey1, pubKey2, err := v1Graph.IsZombieEdge(
5449+
isZombie, pubKey1, pubKey2, err := vGraph.IsZombieEdge(
54255450
ctx, edge.ChannelID,
54265451
)
54275452
require.NoError(t, err)
54285453
require.True(t, isZombie)
54295454
require.Equal(t, node1.PubKeyBytes, pubKey1)
54305455
require.Equal(t, node2.PubKeyBytes, pubKey2)
5431-
assertNumZombies(t, graph, 1)
5456+
assertNumZombies(t, graph, v, 1)
54325457

54335458
// Similarly, if we mark the same edge as live, we should no longer see
54345459
// it within the index.
5435-
err = graph.MarkEdgeLive(ctx, lnwire.GossipVersion1, edge.ChannelID)
5460+
err = graph.MarkEdgeLive(ctx, v, edge.ChannelID)
54365461
require.NoError(t, err)
54375462

54385463
// Attempting to mark the edge as live again now that it is no longer
54395464
// in the zombie index should fail.
54405465
require.ErrorIs(
5441-
t, graph.MarkEdgeLive(
5442-
ctx, lnwire.GossipVersion1, edge.ChannelID,
5443-
),
5466+
t, graph.MarkEdgeLive(ctx, v, edge.ChannelID),
54445467
ErrZombieEdgeNotFound,
54455468
)
54465469

5447-
isZombie, _, _, err = v1Graph.IsZombieEdge(ctx, edge.ChannelID)
5470+
isZombie, _, _, err = vGraph.IsZombieEdge(ctx, edge.ChannelID)
54485471
require.NoError(t, err)
54495472
require.False(t, isZombie)
54505473

5451-
assertNumZombies(t, graph, 0)
5474+
assertNumZombies(t, graph, v, 0)
54525475

54535476
// If we mark the edge as a zombie manually, then it should show up as
54545477
// being a zombie once again.
54555478
err = graph.MarkEdgeZombie(
5456-
ctx, lnwire.GossipVersion1, edge.ChannelID,
5479+
ctx, v, edge.ChannelID,
54575480
node1.PubKeyBytes, node2.PubKeyBytes,
54585481
)
54595482
require.NoError(t, err, "unable to mark edge as zombie")
54605483

5461-
isZombie, _, _, err = v1Graph.IsZombieEdge(ctx, edge.ChannelID)
5484+
isZombie, _, _, err = vGraph.IsZombieEdge(ctx, edge.ChannelID)
54625485
require.NoError(t, err)
54635486
require.True(t, isZombie)
5464-
assertNumZombies(t, graph, 1)
5487+
assertNumZombies(t, graph, v, 1)
54655488
}
54665489

54675490
// compareNodes is used to compare two Nodes.
@@ -5522,33 +5545,50 @@ func compareEdgePolicies(t testing.TB, a, b *models.ChannelEdgePolicy) {
55225545
require.Equal(t, normalizedA, normalizedB)
55235546
}
55245547

5525-
// TestLightningNodeSigVerification checks that we can use the Node's
5526-
// pubkey to verify signatures.
5527-
func TestLightningNodeSigVerification(t *testing.T) {
5548+
// testLightningNodeSigVerification checks that we can use the Node's pubkey to
5549+
// verify signatures. For v1 this exercises ECDSA, for v2 Schnorr.
5550+
func testLightningNodeSigVerification(t *testing.T,
5551+
v lnwire.GossipVersion) {
5552+
55285553
t.Parallel()
55295554

55305555
// Create some dummy data to sign.
55315556
var data [32]byte
55325557
_, err := prand.Read(data[:])
55335558
require.NoError(t, err)
55345559

5535-
// Create private key and sign the data with it.
5560+
// Create private key.
55365561
priv, err := btcec.NewPrivateKey()
5537-
require.NoError(t, err, "unable to crete priv key")
5538-
5539-
sign := ecdsa.Sign(priv, data[:])
5540-
5541-
// Sanity check that the signature checks out.
5542-
require.True(t, sign.Verify(data[:], priv.PubKey()))
5562+
require.NoError(t, err, "unable to create priv key")
55435563

55445564
// Create a Node from the same private key.
5545-
node := createNode(t, lnwire.GossipVersion1, priv)
5565+
node := createNode(t, v, priv)
55465566

5547-
// And finally check that we can verify the same signature from the
5548-
// pubkey returned from the lightning node.
5567+
// Retrieve the public key from the node and verify a signature
5568+
// produced by the same private key.
55495569
nodePub, err := node.PubKey()
55505570
require.NoError(t, err, "unable to get pubkey")
5551-
require.True(t, sign.Verify(data[:], nodePub))
5571+
5572+
// Sign the data using the appropriate scheme for the gossip version.
5573+
// V1 uses ECDSA, v2 uses Schnorr.
5574+
type verifiable interface {
5575+
Verify(hash []byte, pubKey *btcec.PublicKey) bool
5576+
}
5577+
5578+
var sig verifiable
5579+
switch v {
5580+
case lnwire.GossipVersion1:
5581+
sig = ecdsa.Sign(priv, data[:])
5582+
case lnwire.GossipVersion2:
5583+
schnorrSig, sErr := schnorr.Sign(priv, data[:])
5584+
require.NoError(t, sErr)
5585+
sig = schnorrSig
5586+
}
5587+
5588+
// Verify against the raw private key's pubkey, then against the
5589+
// pubkey extracted from the Node.
5590+
require.True(t, sig.Verify(data[:], priv.PubKey()))
5591+
require.True(t, sig.Verify(data[:], nodePub))
55525592
}
55535593

55545594
// TestComputeFee tests fee calculation based on the outgoing amt.

0 commit comments

Comments
 (0)