Skip to content

Commit fe55c94

Browse files
committed
graph/db: migrate source node to SQL store
1 parent 04c00c7 commit fe55c94

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

graph/db/sql_migration.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ func MigrateGraphToSQL(ctx context.Context, kvBackend kvdb.Backend,
4343
return fmt.Errorf("could not migrate nodes: %w", err)
4444
}
4545

46+
// 2) Migrate the source node.
47+
if err := migrateSourceNode(ctx, kvBackend, sqlDB); err != nil {
48+
return fmt.Errorf("could not migrate source node: %w", err)
49+
}
50+
4651
log.Infof("Finished migration of the graph store from KV to SQL in %v",
4752
time.Since(t0))
4853

@@ -184,3 +189,75 @@ func migrateNodes(ctx context.Context, kvBackend kvdb.Backend,
184189

185190
return nil
186191
}
192+
193+
// migrateSourceNode migrates the source node from the KV backend to the
194+
// SQL database.
195+
func migrateSourceNode(ctx context.Context, kvdb kvdb.Backend,
196+
sqlDB SQLQueries) error {
197+
198+
sourceNode, err := sourceNode(kvdb)
199+
if errors.Is(err, ErrSourceNodeNotSet) {
200+
// If the source node has not been set yet, we can skip this
201+
// migration step.
202+
return nil
203+
} else if err != nil {
204+
return fmt.Errorf("could not get source node from kv "+
205+
"store: %w", err)
206+
}
207+
208+
pub := sourceNode.PubKeyBytes
209+
210+
// Get the DB ID of the source node by its public key. This node must
211+
// already exist in the SQL database, as it should have been migrated
212+
// in the previous node-migration step.
213+
id, err := sqlDB.GetNodeIDByPubKey(
214+
ctx, sqlc.GetNodeIDByPubKeyParams{
215+
PubKey: pub[:],
216+
Version: int16(ProtocolV1),
217+
},
218+
)
219+
if err != nil {
220+
return fmt.Errorf("could not get source node ID: %w", err)
221+
}
222+
223+
// Now we can add the source node to the SQL database.
224+
err = sqlDB.AddSourceNode(ctx, id)
225+
if err != nil {
226+
return fmt.Errorf("could not add source node to SQL store: %w",
227+
err)
228+
}
229+
230+
// Verify that the source node was added correctly by fetching it back
231+
// from the SQL database and checking that the expected DB ID and
232+
// pub key are returned. We don't need to do a whole node comparison
233+
// here, as this was already done in the previous migration step.
234+
srcNodes, err := sqlDB.GetSourceNodesByVersion(ctx, int16(ProtocolV1))
235+
if err != nil {
236+
return fmt.Errorf("could not get source nodes from SQL "+
237+
"store: %w", err)
238+
}
239+
240+
// The SQL store has support for multiple source nodes (for future
241+
// protocol versions) but this migration is purely aimed at the V1
242+
// store, and so we expect exactly one source node to be present.
243+
if len(srcNodes) != 1 {
244+
return fmt.Errorf("expected exactly one source node, "+
245+
"got %d", len(srcNodes))
246+
}
247+
248+
// Check that the source node ID and pub key match the original
249+
// source node.
250+
if srcNodes[0].NodeID != id {
251+
return fmt.Errorf("source node ID mismatch after migration: "+
252+
"expected %d, got %d", id, srcNodes[0].NodeID)
253+
}
254+
err = sqldb.CompareRecords(pub[:], srcNodes[0].PubKey, "source node")
255+
if err != nil {
256+
return fmt.Errorf("source node pubkey mismatch after "+
257+
"migration: %w", err)
258+
}
259+
260+
log.Infof("Migrated source node with pubkey %x to SQL", pub[:])
261+
262+
return nil
263+
}

graph/db/sql_migration_test.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package graphdb
55
import (
66
"bytes"
77
"context"
8+
"errors"
89
"fmt"
910
"image/color"
1011
"net"
@@ -106,6 +107,23 @@ func TestMigrateGraphToSQL(t *testing.T) {
106107
numNodes: 6,
107108
},
108109
},
110+
{
111+
name: "source node",
112+
write: func(t *testing.T, db *KVStore, object any) {
113+
node, ok := object.(*models.LightningNode)
114+
require.True(t, ok)
115+
116+
err := db.SetSourceNode(ctx, node)
117+
require.NoError(t, err)
118+
},
119+
objects: []any{
120+
makeTestNode(t),
121+
},
122+
expGraphStats: graphStats{
123+
numNodes: 1,
124+
srcNodeSet: true,
125+
},
126+
},
109127
}
110128

111129
for _, test := range tests {
@@ -138,7 +156,8 @@ func TestMigrateGraphToSQL(t *testing.T) {
138156

139157
// graphStats holds expected statistics about the graph after migration.
140158
type graphStats struct {
141-
numNodes int
159+
numNodes int
160+
srcNodeSet bool
142161
}
143162

144163
// assertInSync checks that the KVStore and SQLStore both contain the same
@@ -150,6 +169,12 @@ func assertInSync(t *testing.T, kvDB *KVStore, sqlDB *SQLStore,
150169
sqlNodes := fetchAllNodes(t, sqlDB)
151170
require.Len(t, sqlNodes, stats.numNodes)
152171
require.Equal(t, fetchAllNodes(t, kvDB), sqlNodes)
172+
173+
// 2) Check that the source nodes match (if indeed source nodes have
174+
// been set).
175+
sqlSourceNode := fetchSourceNode(t, sqlDB)
176+
require.Equal(t, stats.srcNodeSet, sqlSourceNode != nil)
177+
require.Equal(t, fetchSourceNode(t, kvDB), sqlSourceNode)
153178
}
154179

155180
// fetchAllNodes retrieves all nodes from the given store and returns them
@@ -179,6 +204,18 @@ func fetchAllNodes(t *testing.T, store V1Store) []*models.LightningNode {
179204
return nodes
180205
}
181206

207+
// fetchSourceNode retrieves the source node from the given store.
208+
func fetchSourceNode(t *testing.T, store V1Store) *models.LightningNode {
209+
node, err := store.SourceNode(context.Background())
210+
if errors.Is(err, ErrSourceNodeNotSet) {
211+
return nil
212+
} else {
213+
require.NoError(t, err)
214+
}
215+
216+
return node
217+
}
218+
182219
// setUpKVStore initializes a new KVStore for testing.
183220
func setUpKVStore(t *testing.T) *KVStore {
184221
kvDB, cleanup, err := kvdb.GetTestBackend(t.TempDir(), "graph")

0 commit comments

Comments
 (0)