Skip to content

Commit 91432b0

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 310a1b5 commit 91432b0

File tree

2 files changed

+217
-28
lines changed

2 files changed

+217
-28
lines changed

session/sql_migration.go

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

183372
var (
184373
acctID sql.NullInt64
@@ -214,7 +403,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
214403
}
215404

216405
// Proceed to insert the session into the sql db.
217-
sqlId, err := tx.InsertSession(ctx, sqlc.InsertSessionParams{
406+
sqlId, err := tx.InsertSession(ctx, sqlcmig6.InsertSessionParams{
218407
Alias: session.ID[:],
219408
Label: session.Label,
220409
State: int16(session.State),
@@ -240,7 +429,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
240429
// has been created.
241430
if !session.RevokedAt.IsZero() {
242431
err = tx.SetSessionRevokedAt(
243-
ctx, sqlc.SetSessionRevokedAtParams{
432+
ctx, sqlcmig6.SetSessionRevokedAtParams{
244433
ID: sqlId,
245434
RevokedAt: sqldb.SQLTime(
246435
session.RevokedAt.UTC(),
@@ -266,7 +455,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
266455
}
267456

268457
// Now lets set the group ID for the session.
269-
err = tx.SetSessionGroupID(ctx, sqlc.SetSessionGroupIDParams{
458+
err = tx.SetSessionGroupID(ctx, sqlcmig6.SetSessionGroupIDParams{
270459
ID: sqlId,
271460
GroupID: sqldb.SQLInt64(groupID),
272461
})
@@ -280,7 +469,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
280469
// We start by inserting the macaroon permissions.
281470
for _, sessionPerm := range session.MacaroonRecipe.Permissions {
282471
err = tx.InsertSessionMacaroonPermission(
283-
ctx, sqlc.InsertSessionMacaroonPermissionParams{
472+
ctx, sqlcmig6.InsertSessionMacaroonPermissionParams{
284473
SessionID: sqlId,
285474
Entity: sessionPerm.Entity,
286475
Action: sessionPerm.Action,
@@ -294,7 +483,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
294483
// Next we insert the macaroon caveats.
295484
for _, caveat := range session.MacaroonRecipe.Caveats {
296485
err = tx.InsertSessionMacaroonCaveat(
297-
ctx, sqlc.InsertSessionMacaroonCaveatParams{
486+
ctx, sqlcmig6.InsertSessionMacaroonCaveatParams{
298487
SessionID: sqlId,
299488
CaveatID: caveat.Id,
300489
VerificationID: caveat.VerificationId,
@@ -313,7 +502,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
313502
if session.FeatureConfig != nil {
314503
for featureName, config := range *session.FeatureConfig {
315504
err = tx.InsertSessionFeatureConfig(
316-
ctx, sqlc.InsertSessionFeatureConfigParams{
505+
ctx, sqlcmig6.InsertSessionFeatureConfigParams{
317506
SessionID: sqlId,
318507
FeatureName: featureName,
319508
Config: config,
@@ -328,7 +517,7 @@ func migrateSingleSessionToSQL(ctx context.Context,
328517
// Finally we insert the privacy flags.
329518
for _, privacyFlag := range session.PrivacyFlags {
330519
err = tx.InsertSessionPrivacyFlag(
331-
ctx, sqlc.InsertSessionPrivacyFlagParams{
520+
ctx, sqlcmig6.InsertSessionPrivacyFlagParams{
332521
SessionID: sqlId,
333522
Flag: int32(privacyFlag),
334523
},

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)