Skip to content

Commit e1253ce

Browse files
session: add deterministic map compare
This commit adds a deterministic comparison for the maps in sessions during the KVDB to SQL migration.
1 parent 3b51680 commit e1253ce

File tree

1 file changed

+89
-4
lines changed

1 file changed

+89
-4
lines changed

session/sql_migration.go

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ 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"
1517
"github.com/lightninglabs/lightning-terminal/db/sqlc"
18+
"github.com/lightningnetwork/lnd/fn"
1619
"github.com/lightningnetwork/lnd/sqldb"
1720
"github.com/pmezard/go-difflib/difflib"
1821
"go.etcd.io/bbolt"
@@ -25,6 +28,85 @@ var (
2528
"original session")
2629
)
2730

31+
// featureConfigEntry is a variant of a single session feature config, which
32+
// can be inserted into an array to be compared deterministically.
33+
type featureConfigEntry struct {
34+
featureName string
35+
config []byte
36+
}
37+
38+
// deterministicSession is a variant of the Session struct without any struct
39+
// methods, which represents the map in the Session as a list, so that it can be
40+
// deterministically sorted for comparison during the kvdb to SQL migration.
41+
type deterministicSession struct {
42+
ID ID
43+
Label string
44+
State State
45+
Type Type
46+
Expiry time.Time
47+
CreatedAt time.Time
48+
RevokedAt time.Time
49+
ServerAddr string
50+
DevServer bool
51+
MacaroonRootKey uint64
52+
MacaroonRecipe *MacaroonRecipe
53+
PairingSecret [mailbox.NumPassphraseEntropyBytes]byte
54+
LocalPrivateKey *btcec.PrivateKey
55+
LocalPublicKey *btcec.PublicKey
56+
RemotePublicKey *btcec.PublicKey
57+
FeatureConfig []*featureConfigEntry
58+
WithPrivacyMapper bool
59+
PrivacyFlags PrivacyFlags
60+
61+
// GroupID is the Session ID of the very first Session in the linked
62+
// group of sessions. If this is the very first session in the group
63+
// then this will be the same as ID.
64+
GroupID ID
65+
66+
// AccountID is an optional account that the session has been linked to.
67+
AccountID fn.Option[accounts.AccountID]
68+
}
69+
70+
// newDeterministicSession creates a deterministicSession from a Session struct.
71+
// This is used to compare the session in a deterministic way during the
72+
// migration from the KV database to the SQL database.
73+
func newDeterministicSession(sess *Session) *deterministicSession {
74+
sessFC := *sess.FeatureConfig
75+
featuresConfig := make([]*featureConfigEntry, len(sessFC))
76+
77+
i := 0
78+
for featureName, config := range sessFC {
79+
featuresConfig[i] = &featureConfigEntry{
80+
featureName: featureName,
81+
config: config,
82+
}
83+
84+
i++
85+
}
86+
87+
return &deterministicSession{
88+
ID: sess.ID,
89+
Label: sess.Label,
90+
State: sess.State,
91+
Type: sess.Type,
92+
Expiry: sess.Expiry,
93+
CreatedAt: sess.CreatedAt,
94+
RevokedAt: sess.RevokedAt,
95+
ServerAddr: sess.ServerAddr,
96+
DevServer: sess.DevServer,
97+
MacaroonRootKey: sess.MacaroonRootKey,
98+
PairingSecret: sess.PairingSecret,
99+
LocalPrivateKey: sess.LocalPrivateKey,
100+
LocalPublicKey: sess.LocalPublicKey,
101+
RemotePublicKey: sess.RemotePublicKey,
102+
GroupID: sess.GroupID,
103+
AccountID: sess.AccountID,
104+
PrivacyFlags: sess.PrivacyFlags,
105+
MacaroonRecipe: sess.MacaroonRecipe,
106+
WithPrivacyMapper: sess.WithPrivacyMapper,
107+
}
108+
}
109+
28110
// MigrateSessionStoreToSQL runs the migration of all sessions from the KV
29111
// database to the SQL database. The migration is done in a single transaction
30112
// to ensure that all sessions are migrated or none at all.
@@ -149,13 +231,16 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
149231
overrideSessionTimeZone(migratedSession)
150232
overrideMacaroonRecipe(kvSession, migratedSession)
151233

152-
if !reflect.DeepEqual(kvSession, migratedSession) {
234+
dKvSession := newDeterministicSession(kvSession)
235+
dMigratedSession := newDeterministicSession(migratedSession)
236+
237+
if !reflect.DeepEqual(dKvSession, dMigratedSession) {
153238
diff := difflib.UnifiedDiff{
154239
A: difflib.SplitLines(
155-
spew.Sdump(kvSession),
240+
spew.Sdump(dKvSession),
156241
),
157242
B: difflib.SplitLines(
158-
spew.Sdump(migratedSession),
243+
spew.Sdump(dMigratedSession),
159244
),
160245
FromFile: "Expected",
161246
FromDate: "",
@@ -166,7 +251,7 @@ func migrateSessionsToSQLAndValidate(ctx context.Context,
166251
diffText, _ := difflib.GetUnifiedDiffString(diff)
167252

168253
return fmt.Errorf("%w: %v.\n%v", ErrMigrationMismatch,
169-
kvSession.ID, diffText)
254+
dKvSession.ID, diffText)
170255
}
171256
}
172257

0 commit comments

Comments
 (0)