Skip to content

Commit 62ec707

Browse files
committed
session: use sqlcmig6 for kvdb to sql migration
This commit updates the session package to use the new `sqlcmig6` package for kvdb to SQL migration.
1 parent 2d95660 commit 62ec707

File tree

2 files changed

+218
-28
lines changed

2 files changed

+218
-28
lines changed

session/sql_migration.go

Lines changed: 213 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ import (
1010
"sort"
1111
"time"
1212

13+
"github.com/btcsuite/btcd/btcec/v2"
1314
"github.com/davecgh/go-spew/spew"
15+
"github.com/lightninglabs/lightning-node-connect/mailbox"
1416
"github.com/lightninglabs/lightning-terminal/accounts"
15-
"github.com/lightninglabs/lightning-terminal/db/sqlc"
17+
"github.com/lightninglabs/lightning-terminal/db/sqlcmig6"
18+
"github.com/lightningnetwork/lnd/fn"
1619
"github.com/lightningnetwork/lnd/sqldb"
1720
"github.com/pmezard/go-difflib/difflib"
1821
"go.etcd.io/bbolt"
22+
"gopkg.in/macaroon-bakery.v2/bakery"
23+
"gopkg.in/macaroon.v2"
1924
)
2025

2126
var (
@@ -32,7 +37,7 @@ var (
3237
// NOTE: As sessions may contain linked accounts, the accounts sql migration
3338
// MUST be run prior to this migration.
3439
func MigrateSessionStoreToSQL(ctx context.Context, kvStore *bbolt.DB,
35-
tx SQLQueries) error {
40+
tx *sqlcmig6.Queries) error {
3641

3742
log.Infof("Starting migration of the KV sessions store to SQL")
3843

@@ -119,7 +124,7 @@ func getBBoltSessions(db *bbolt.DB) ([]*Session, error) {
119124
// from the KV database to the SQL database, and validates that the migrated
120125
// sessions match the original sessions.
121126
func migrateSessionsToSQLAndValidate(ctx context.Context,
122-
tx SQLQueries, kvSessions []*Session) error {
127+
tx *sqlcmig6.Queries, kvSessions []*Session) error {
123128

124129
for _, kvSession := range kvSessions {
125130
err := migrateSingleSessionToSQL(ctx, tx, kvSession)
@@ -128,18 +133,9 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
128133
kvSession.ID, err)
129134
}
130135

131-
// Validate that the session was correctly migrated and matches
132-
// the original session in the kv store.
133-
sqlSess, err := tx.GetSessionByAlias(ctx, kvSession.ID[:])
134-
if err != nil {
135-
if errors.Is(err, sql.ErrNoRows) {
136-
err = ErrSessionNotFound
137-
}
138-
return fmt.Errorf("unable to get migrated session "+
139-
"from sql store: %w", err)
140-
}
141-
142-
migratedSession, err := unmarshalSession(ctx, tx, sqlSess)
136+
migratedSession, err := getAndUnmarshalSession(
137+
ctx, tx, kvSession.ID[:],
138+
)
143139
if err != nil {
144140
return fmt.Errorf("unable to unmarshal migrated "+
145141
"session: %w", err)
@@ -173,12 +169,206 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
173169
return nil
174170
}
175171

172+
func getAndUnmarshalSession(ctx context.Context,
173+
tx *sqlcmig6.Queries, legacyID []byte) (*Session, error) {
174+
175+
// Validate that the session was correctly migrated and matches
176+
// the original session in the kv store.
177+
sqlSess, err := tx.GetSessionByAlias(ctx, legacyID)
178+
if err != nil {
179+
if errors.Is(err, sql.ErrNoRows) {
180+
err = ErrSessionNotFound
181+
}
182+
183+
return nil, fmt.Errorf("unable to get migrated session "+
184+
"from sql store: %w", err)
185+
}
186+
187+
migratedSession, err := unmarshalMig6Session(ctx, tx, sqlSess)
188+
if err != nil {
189+
return nil, fmt.Errorf("unable to unmarshal migrated "+
190+
"session: %w", err)
191+
}
192+
193+
return migratedSession, nil
194+
195+
}
196+
197+
func unmarshalMig6Session(ctx context.Context, db *sqlcmig6.Queries,
198+
dbSess sqlcmig6.Session) (*Session, error) {
199+
200+
var legacyGroupID ID
201+
if dbSess.GroupID.Valid {
202+
groupID, err := db.GetAliasBySessionID(
203+
ctx, dbSess.GroupID.Int64,
204+
)
205+
if err != nil {
206+
return nil, fmt.Errorf("unable to get legacy group "+
207+
"Alias: %v", err)
208+
}
209+
210+
legacyGroupID, err = IDFromBytes(groupID)
211+
if err != nil {
212+
return nil, fmt.Errorf("unable to get legacy Alias: %v",
213+
err)
214+
}
215+
}
216+
217+
var acctAlias fn.Option[accounts.AccountID]
218+
if dbSess.AccountID.Valid {
219+
account, err := db.GetAccount(ctx, dbSess.AccountID.Int64)
220+
if err != nil {
221+
return nil, fmt.Errorf("unable to get account: %v", err)
222+
}
223+
224+
accountAlias, err := accounts.AccountIDFromInt64(account.Alias)
225+
if err != nil {
226+
return nil, fmt.Errorf("unable to get account ID: %v", err)
227+
}
228+
acctAlias = fn.Some(accountAlias)
229+
}
230+
231+
legacyID, err := IDFromBytes(dbSess.Alias)
232+
if err != nil {
233+
return nil, fmt.Errorf("unable to get legacy Alias: %v", err)
234+
}
235+
236+
var revokedAt time.Time
237+
if dbSess.RevokedAt.Valid {
238+
revokedAt = dbSess.RevokedAt.Time
239+
}
240+
241+
localPriv, localPub := btcec.PrivKeyFromBytes(dbSess.LocalPrivateKey)
242+
243+
var remotePub *btcec.PublicKey
244+
if len(dbSess.RemotePublicKey) != 0 {
245+
remotePub, err = btcec.ParsePubKey(dbSess.RemotePublicKey)
246+
if err != nil {
247+
return nil, fmt.Errorf("unable to parse remote "+
248+
"public key: %v", err)
249+
}
250+
}
251+
252+
// Get the macaroon permissions if they exist.
253+
perms, err := db.GetSessionMacaroonPermissions(ctx, dbSess.ID)
254+
if err != nil {
255+
return nil, fmt.Errorf("unable to get macaroon "+
256+
"permissions: %v", err)
257+
}
258+
259+
// Get the macaroon caveats if they exist.
260+
caveats, err := db.GetSessionMacaroonCaveats(ctx, dbSess.ID)
261+
if err != nil {
262+
return nil, fmt.Errorf("unable to get macaroon "+
263+
"caveats: %v", err)
264+
}
265+
266+
var macRecipe *MacaroonRecipe
267+
if perms != nil || caveats != nil {
268+
macRecipe = &MacaroonRecipe{
269+
Permissions: unmarshalMig6MacPerms(perms),
270+
Caveats: unmarshalMig6MacCaveats(caveats),
271+
}
272+
}
273+
274+
// Get the feature configs if they exist.
275+
featureConfigs, err := db.GetSessionFeatureConfigs(ctx, dbSess.ID)
276+
if err != nil {
277+
return nil, fmt.Errorf("unable to get feature configs: %v", err)
278+
}
279+
280+
var featureCfgs *FeaturesConfig
281+
if featureConfigs != nil {
282+
featureCfgs = unmarshalMig6FeatureConfigs(featureConfigs)
283+
}
284+
285+
// Get the privacy flags if they exist.
286+
privacyFlags, err := db.GetSessionPrivacyFlags(ctx, dbSess.ID)
287+
if err != nil {
288+
return nil, fmt.Errorf("unable to get privacy flags: %v", err)
289+
}
290+
291+
var privFlags PrivacyFlags
292+
if privacyFlags != nil {
293+
privFlags = unmarshalMig6PrivacyFlags(privacyFlags)
294+
}
295+
296+
var pairingSecret [mailbox.NumPassphraseEntropyBytes]byte
297+
copy(pairingSecret[:], dbSess.PairingSecret)
298+
299+
return &Session{
300+
ID: legacyID,
301+
Label: dbSess.Label,
302+
State: State(dbSess.State),
303+
Type: Type(dbSess.Type),
304+
Expiry: dbSess.Expiry,
305+
CreatedAt: dbSess.CreatedAt,
306+
RevokedAt: revokedAt,
307+
ServerAddr: dbSess.ServerAddress,
308+
DevServer: dbSess.DevServer,
309+
MacaroonRootKey: uint64(dbSess.MacaroonRootKey),
310+
PairingSecret: pairingSecret,
311+
LocalPrivateKey: localPriv,
312+
LocalPublicKey: localPub,
313+
RemotePublicKey: remotePub,
314+
WithPrivacyMapper: dbSess.Privacy,
315+
GroupID: legacyGroupID,
316+
PrivacyFlags: privFlags,
317+
MacaroonRecipe: macRecipe,
318+
FeatureConfig: featureCfgs,
319+
AccountID: acctAlias,
320+
}, nil
321+
}
322+
323+
func unmarshalMig6MacPerms(dbPerms []sqlcmig6.SessionMacaroonPermission) []bakery.Op {
324+
ops := make([]bakery.Op, len(dbPerms))
325+
for i, dbPerm := range dbPerms {
326+
ops[i] = bakery.Op{
327+
Entity: dbPerm.Entity,
328+
Action: dbPerm.Action,
329+
}
330+
}
331+
332+
return ops
333+
}
334+
335+
func unmarshalMig6MacCaveats(dbCaveats []sqlcmig6.SessionMacaroonCaveat) []macaroon.Caveat {
336+
caveats := make([]macaroon.Caveat, len(dbCaveats))
337+
for i, dbCaveat := range dbCaveats {
338+
caveats[i] = macaroon.Caveat{
339+
Id: dbCaveat.CaveatID,
340+
VerificationId: dbCaveat.VerificationID,
341+
Location: dbCaveat.Location.String,
342+
}
343+
}
344+
345+
return caveats
346+
}
347+
348+
func unmarshalMig6FeatureConfigs(dbConfigs []sqlcmig6.SessionFeatureConfig) *FeaturesConfig {
349+
configs := make(FeaturesConfig, len(dbConfigs))
350+
for _, dbConfig := range dbConfigs {
351+
configs[dbConfig.FeatureName] = dbConfig.Config
352+
}
353+
354+
return &configs
355+
}
356+
357+
func unmarshalMig6PrivacyFlags(dbFlags []sqlcmig6.SessionPrivacyFlag) PrivacyFlags {
358+
flags := make(PrivacyFlags, len(dbFlags))
359+
for i, dbFlag := range dbFlags {
360+
flags[i] = PrivacyFlag(dbFlag.Flag)
361+
}
362+
363+
return flags
364+
}
365+
176366
// migrateSingleSessionToSQL runs the migration for a single session from the
177367
// KV database to the SQL database. Note that if the session links to an
178368
// account, the linked accounts store MUST have been migrated before that
179369
// session is migrated.
180370
func migrateSingleSessionToSQL(ctx context.Context,
181-
tx SQLQueries, session *Session) error {
371+
tx *sqlcmig6.Queries, session *Session) error {
182372

183373
var (
184374
acctID sql.NullInt64
@@ -214,7 +404,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
214404
}
215405

216406
// Proceed to insert the session into the sql db.
217-
sqlId, err := tx.InsertSession(ctx, sqlc.InsertSessionParams{
407+
sqlId, err := tx.InsertSession(ctx, sqlcmig6.InsertSessionParams{
218408
Alias: session.ID[:],
219409
Label: session.Label,
220410
State: int16(session.State),
@@ -240,7 +430,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
240430
// has been created.
241431
if !session.RevokedAt.IsZero() {
242432
err = tx.SetSessionRevokedAt(
243-
ctx, sqlc.SetSessionRevokedAtParams{
433+
ctx, sqlcmig6.SetSessionRevokedAtParams{
244434
ID: sqlId,
245435
RevokedAt: sqldb.SQLTime(
246436
session.RevokedAt.UTC(),
@@ -266,7 +456,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
266456
}
267457

268458
// Now lets set the group ID for the session.
269-
err = tx.SetSessionGroupID(ctx, sqlc.SetSessionGroupIDParams{
459+
err = tx.SetSessionGroupID(ctx, sqlcmig6.SetSessionGroupIDParams{
270460
ID: sqlId,
271461
GroupID: sqldb.SQLInt64(groupID),
272462
})
@@ -280,7 +470,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
280470
// We start by inserting the macaroon permissions.
281471
for _, sessionPerm := range session.MacaroonRecipe.Permissions {
282472
err = tx.InsertSessionMacaroonPermission(
283-
ctx, sqlc.InsertSessionMacaroonPermissionParams{
473+
ctx, sqlcmig6.InsertSessionMacaroonPermissionParams{
284474
SessionID: sqlId,
285475
Entity: sessionPerm.Entity,
286476
Action: sessionPerm.Action,
@@ -294,7 +484,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
294484
// Next we insert the macaroon caveats.
295485
for _, caveat := range session.MacaroonRecipe.Caveats {
296486
err = tx.InsertSessionMacaroonCaveat(
297-
ctx, sqlc.InsertSessionMacaroonCaveatParams{
487+
ctx, sqlcmig6.InsertSessionMacaroonCaveatParams{
298488
SessionID: sqlId,
299489
CaveatID: caveat.Id,
300490
VerificationID: caveat.VerificationId,
@@ -313,7 +503,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
313503
if session.FeatureConfig != nil {
314504
for featureName, config := range *session.FeatureConfig {
315505
err = tx.InsertSessionFeatureConfig(
316-
ctx, sqlc.InsertSessionFeatureConfigParams{
506+
ctx, sqlcmig6.InsertSessionFeatureConfigParams{
317507
SessionID: sqlId,
318508
FeatureName: featureName,
319509
Config: config,
@@ -328,7 +518,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
328518
// Finally we insert the privacy flags.
329519
for _, privacyFlag := range session.PrivacyFlags {
330520
err = tx.InsertSessionPrivacyFlag(
331-
ctx, sqlc.InsertSessionPrivacyFlagParams{
521+
ctx, sqlcmig6.InsertSessionPrivacyFlagParams{
332522
SessionID: sqlId,
333523
Flag: int32(privacyFlag),
334524
},

session/sql_migration_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"time"
88

99
"github.com/lightninglabs/lightning-terminal/accounts"
10-
"github.com/lightninglabs/lightning-terminal/db/sqlc"
10+
"github.com/lightninglabs/lightning-terminal/db/sqlcmig6"
1111
"github.com/lightningnetwork/lnd/clock"
1212
"github.com/lightningnetwork/lnd/lnwire"
1313
"github.com/lightningnetwork/lnd/macaroons"
@@ -37,7 +37,7 @@ func TestSessionsStoreMigration(t *testing.T) {
3737
}
3838

3939
makeSQLDB := func(t *testing.T, acctStore accounts.Store) (*SQLStore,
40-
*SQLQueriesExecutor[SQLQueries]) {
40+
*sqlcmig6.TxExecutor[*sqlcmig6.Queries]) {
4141

4242
// Create a sql store with a linked account store.
4343
testDBStore := NewTestDBWithAccounts(t, clock, acctStore)
@@ -47,9 +47,9 @@ func TestSessionsStoreMigration(t *testing.T) {
4747

4848
baseDB := store.BaseDB
4949

50-
queries := sqlc.NewForType(baseDB, baseDB.BackendType)
50+
queries := sqlcmig6.NewForType(baseDB, baseDB.BackendType)
5151

52-
return store, NewSQLQueriesExecutor(baseDB, queries)
52+
return store, sqlcmig6.NewTxExecutor(baseDB, queries)
5353
}
5454

5555
// assertMigrationResults asserts that the sql store contains the
@@ -366,7 +366,7 @@ func TestSessionsStoreMigration(t *testing.T) {
366366

367367
err = txEx.ExecTx(
368368
ctx, sqldb.WriteTxOpt(),
369-
func(tx SQLQueries) error {
369+
func(tx *sqlcmig6.Queries) error {
370370
return MigrateSessionStoreToSQL(
371371
ctx, kvStore.DB, tx,
372372
)

0 commit comments

Comments
 (0)