Skip to content

Commit 642a69f

Browse files
committed
firewalldb: best effort link from actions to accounts
In this commit, we do our best to ensure that at least at the time of action creation, if the account ID is set, then our bbolt actions store impl will at least first check that the account really does exist. This also forces us to update our tests in preparation for the SQL store which will tightly couple the actions and accounts.
1 parent 26d028f commit 642a69f

File tree

7 files changed

+56
-12
lines changed

7 files changed

+56
-12
lines changed

config_dev.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ func NewStores(cfg *Config, clock clock.Clock) (*stores, error) {
154154
}
155155

156156
firewallBoltDB, err := firewalldb.NewBoltDB(
157-
networkDir, firewalldb.DBFilename, stores.sessions, clock,
157+
networkDir, firewalldb.DBFilename, stores.sessions,
158+
stores.accounts, clock,
158159
)
159160
if err != nil {
160161
return stores, fmt.Errorf("error creating firewall BoltDB: %v",

config_prod.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ func NewStores(cfg *Config, clock clock.Clock) (*stores, error) {
5656
stores.closeFns["sessions"] = sessStore.Close
5757

5858
firewallDB, err := firewalldb.NewBoltDB(
59-
networkDir, firewalldb.DBFilename, sessStore, clock,
59+
networkDir, firewalldb.DBFilename, stores.sessions,
60+
stores.accounts, clock,
6061
)
6162
if err != nil {
6263
return stores, fmt.Errorf("error creating firewall DB: %v", err)

firewalldb/actions_kvdb.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"io"
1010
"time"
1111

12+
"github.com/lightninglabs/lightning-terminal/accounts"
1213
"github.com/lightninglabs/lightning-terminal/session"
1314
"github.com/lightningnetwork/lnd/fn"
1415
"github.com/lightningnetwork/lnd/tlv"
@@ -69,6 +70,17 @@ func (db *BoltDB) AddAction(ctx context.Context,
6970
return nil, err
7071
}
7172

73+
// If the new action links to an account, the account must exist.
74+
// For the bbolt impl of the store, this is our best effort attempt
75+
// at ensuring each action links to an account. If the account is
76+
// deleted later on, however, then the action will still exist.
77+
req.AccountID.WhenSome(func(id accounts.AccountID) {
78+
_, err = db.accountsDB.Account(ctx, id)
79+
})
80+
if err != nil {
81+
return nil, err
82+
}
83+
7284
action := &Action{
7385
AddActionReq: *req,
7486
AttemptedAt: db.clock.Now().UTC(),

firewalldb/actions_test.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77
"time"
88

9+
"github.com/lightninglabs/lightning-terminal/accounts"
910
"github.com/lightninglabs/lightning-terminal/session"
1011
"github.com/lightningnetwork/lnd/clock"
1112
"github.com/lightningnetwork/lnd/fn"
@@ -24,8 +25,9 @@ func TestActionStorage(t *testing.T) {
2425
ctx := context.Background()
2526
clock := clock.NewTestClock(testTime1)
2627
sessDB := session.NewTestDB(t, clock)
28+
accountsDB := accounts.NewTestDB(t, clock)
2729

28-
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, clock)
30+
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, accountsDB, clock)
2931
require.NoError(t, err)
3032
t.Cleanup(func() {
3133
_ = db.Close()
@@ -38,6 +40,13 @@ func TestActionStorage(t *testing.T) {
3840
})
3941
require.ErrorIs(t, err, session.ErrSessionNotFound)
4042

43+
// Assert that attempting to add an action that links to an account
44+
// that does not exist returns an error.
45+
_, err = db.AddAction(ctx, &AddActionReq{
46+
AccountID: fn.Some(accounts.AccountID{1, 2, 3, 4}),
47+
})
48+
require.ErrorIs(t, err, accounts.ErrAccNotFound)
49+
4150
// Add two sessions to the session DB so that we can reference them.
4251
sess1, err := sessDB.NewSession(
4352
ctx, "sess 1", session.TypeAutopilot, time.Unix(1000, 0),
@@ -51,8 +60,13 @@ func TestActionStorage(t *testing.T) {
5160
)
5261
require.NoError(t, err)
5362

63+
// Add an account that we can link to as well.
64+
acct1, err := accountsDB.NewAccount(ctx, 0, time.Time{}, "foo")
65+
require.NoError(t, err)
66+
5467
action1Req := &AddActionReq{
5568
SessionID: fn.Some(sess1.ID),
69+
AccountID: fn.Some(acct1.ID),
5670
MacaroonIdentifier: sess1.ID,
5771
ActorName: "Autopilot",
5872
FeatureName: "auto-fees",
@@ -185,7 +199,7 @@ func TestListActions(t *testing.T) {
185199
clock := clock.NewDefaultClock()
186200
sessDB := session.NewTestDB(t, clock)
187201

188-
db, err := NewBoltDB(tmpDir, "test.db", sessDB, clock)
202+
db, err := NewBoltDB(tmpDir, "test.db", sessDB, nil, clock)
189203
require.NoError(t, err)
190204
t.Cleanup(func() {
191205
_ = db.Close()
@@ -452,7 +466,7 @@ func TestListGroupActions(t *testing.T) {
452466
State: ActionStateInit,
453467
}
454468

455-
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, clock)
469+
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, nil, clock)
456470
require.NoError(t, err)
457471
t.Cleanup(func() {
458472
_ = db.Close()
@@ -490,6 +504,9 @@ func TestListGroupActions(t *testing.T) {
490504
}
491505

492506
func assertEqualActions(t *testing.T, expected, got *Action) {
507+
// Accounts are not explicitly linked in our bbolt DB implementation.
508+
got.AccountID = expected.AccountID
509+
493510
expectedAttemptedAt := expected.AttemptedAt
494511
actualAttemptedAt := got.AttemptedAt
495512

@@ -501,4 +518,6 @@ func assertEqualActions(t *testing.T, expected, got *Action) {
501518

502519
expected.AttemptedAt = expectedAttemptedAt
503520
got.AttemptedAt = actualAttemptedAt
521+
522+
got.AccountID = fn.None[accounts.AccountID]()
504523
}

firewalldb/interface.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package firewalldb
33
import (
44
"context"
55

6+
"github.com/lightninglabs/lightning-terminal/accounts"
67
"github.com/lightninglabs/lightning-terminal/session"
78
)
89

@@ -15,6 +16,15 @@ type SessionDB interface {
1516
GetSession(context.Context, session.ID) (*session.Session, error)
1617
}
1718

19+
// AccountsDB is an interface that abstracts the database operations needed
20+
// firewalldb to be able to query the accounts database.
21+
type AccountsDB interface {
22+
// Account fetches the Account with the given id from the accounts
23+
// database.
24+
Account(ctx context.Context,
25+
id accounts.AccountID) (*accounts.OffChainBalanceAccount, error)
26+
}
27+
1828
// DBExecutor provides an Update and View method that will allow the caller
1929
// to perform atomic read and write transactions defined by PrivacyMapTx on the
2030
// underlying BoltDB.

firewalldb/kvdb_store.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@ type BoltDB struct {
4141
clock clock.Clock
4242

4343
sessionIDIndex SessionDB
44+
accountsDB AccountsDB
4445
}
4546

4647
// NewBoltDB creates a new bolt database that can be found at the given
4748
// directory.
4849
func NewBoltDB(dir, fileName string, sessionIDIndex SessionDB,
49-
clock clock.Clock) (*BoltDB, error) {
50+
accountsDB AccountsDB, clock clock.Clock) (*BoltDB, error) {
5051

5152
firstInit := false
5253
path := filepath.Join(dir, fileName)
@@ -73,6 +74,7 @@ func NewBoltDB(dir, fileName string, sessionIDIndex SessionDB,
7374
return &BoltDB{
7475
DB: db,
7576
sessionIDIndex: sessionIDIndex,
77+
accountsDB: accountsDB,
7678
clock: clock,
7779
}, nil
7880
}

firewalldb/test_kvdb.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package firewalldb
55
import (
66
"testing"
77

8-
"github.com/lightninglabs/lightning-terminal/session"
98
"github.com/lightningnetwork/lnd/clock"
109
"github.com/stretchr/testify/require"
1110
)
@@ -18,21 +17,21 @@ func NewTestDB(t *testing.T, clock clock.Clock) *BoltDB {
1817
// NewTestDBFromPath is a helper function that creates a new BoltStore with a
1918
// connection to an existing BBolt database for testing.
2019
func NewTestDBFromPath(t *testing.T, dbPath string, clock clock.Clock) *BoltDB {
21-
return newDBFromPathWithSessions(t, dbPath, nil, clock)
20+
return newDBFromPathWithSessions(t, dbPath, nil, nil, clock)
2221
}
2322

2423
// NewTestDBWithSessions creates a new test BoltDB Store with access to an
2524
// existing sessions DB.
26-
func NewTestDBWithSessions(t *testing.T, sessStore session.Store,
25+
func NewTestDBWithSessions(t *testing.T, sessStore SessionDB,
2726
clock clock.Clock) *BoltDB {
2827

29-
return newDBFromPathWithSessions(t, t.TempDir(), sessStore, clock)
28+
return newDBFromPathWithSessions(t, t.TempDir(), sessStore, nil, clock)
3029
}
3130

3231
func newDBFromPathWithSessions(t *testing.T, dbPath string,
33-
sessStore session.Store, clock clock.Clock) *BoltDB {
32+
sessStore SessionDB, acctStore AccountsDB, clock clock.Clock) *BoltDB {
3433

35-
store, err := NewBoltDB(dbPath, DBFilename, sessStore, clock)
34+
store, err := NewBoltDB(dbPath, DBFilename, sessStore, acctStore, clock)
3635
require.NoError(t, err)
3736

3837
t.Cleanup(func() {

0 commit comments

Comments
 (0)