mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
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.
This commit is contained in:
parent
26d028f4a5
commit
642a69f1c2
7 changed files with 56 additions and 12 deletions
|
|
@ -154,7 +154,8 @@ func NewStores(cfg *Config, clock clock.Clock) (*stores, error) {
|
|||
}
|
||||
|
||||
firewallBoltDB, err := firewalldb.NewBoltDB(
|
||||
networkDir, firewalldb.DBFilename, stores.sessions, clock,
|
||||
networkDir, firewalldb.DBFilename, stores.sessions,
|
||||
stores.accounts, clock,
|
||||
)
|
||||
if err != nil {
|
||||
return stores, fmt.Errorf("error creating firewall BoltDB: %v",
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ func NewStores(cfg *Config, clock clock.Clock) (*stores, error) {
|
|||
stores.closeFns["sessions"] = sessStore.Close
|
||||
|
||||
firewallDB, err := firewalldb.NewBoltDB(
|
||||
networkDir, firewalldb.DBFilename, sessStore, clock,
|
||||
networkDir, firewalldb.DBFilename, stores.sessions,
|
||||
stores.accounts, clock,
|
||||
)
|
||||
if err != nil {
|
||||
return stores, fmt.Errorf("error creating firewall DB: %v", err)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/accounts"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
|
|
@ -69,6 +70,17 @@ func (db *BoltDB) AddAction(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// If the new action links to an account, the account must exist.
|
||||
// For the bbolt impl of the store, this is our best effort attempt
|
||||
// at ensuring each action links to an account. If the account is
|
||||
// deleted later on, however, then the action will still exist.
|
||||
req.AccountID.WhenSome(func(id accounts.AccountID) {
|
||||
_, err = db.accountsDB.Account(ctx, id)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
action := &Action{
|
||||
AddActionReq: *req,
|
||||
AttemptedAt: db.clock.Now().UTC(),
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/accounts"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
|
|
@ -24,8 +25,9 @@ func TestActionStorage(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
clock := clock.NewTestClock(testTime1)
|
||||
sessDB := session.NewTestDB(t, clock)
|
||||
accountsDB := accounts.NewTestDB(t, clock)
|
||||
|
||||
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, clock)
|
||||
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, accountsDB, clock)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = db.Close()
|
||||
|
|
@ -38,6 +40,13 @@ func TestActionStorage(t *testing.T) {
|
|||
})
|
||||
require.ErrorIs(t, err, session.ErrSessionNotFound)
|
||||
|
||||
// Assert that attempting to add an action that links to an account
|
||||
// that does not exist returns an error.
|
||||
_, err = db.AddAction(ctx, &AddActionReq{
|
||||
AccountID: fn.Some(accounts.AccountID{1, 2, 3, 4}),
|
||||
})
|
||||
require.ErrorIs(t, err, accounts.ErrAccNotFound)
|
||||
|
||||
// Add two sessions to the session DB so that we can reference them.
|
||||
sess1, err := sessDB.NewSession(
|
||||
ctx, "sess 1", session.TypeAutopilot, time.Unix(1000, 0),
|
||||
|
|
@ -51,8 +60,13 @@ func TestActionStorage(t *testing.T) {
|
|||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add an account that we can link to as well.
|
||||
acct1, err := accountsDB.NewAccount(ctx, 0, time.Time{}, "foo")
|
||||
require.NoError(t, err)
|
||||
|
||||
action1Req := &AddActionReq{
|
||||
SessionID: fn.Some(sess1.ID),
|
||||
AccountID: fn.Some(acct1.ID),
|
||||
MacaroonIdentifier: sess1.ID,
|
||||
ActorName: "Autopilot",
|
||||
FeatureName: "auto-fees",
|
||||
|
|
@ -185,7 +199,7 @@ func TestListActions(t *testing.T) {
|
|||
clock := clock.NewDefaultClock()
|
||||
sessDB := session.NewTestDB(t, clock)
|
||||
|
||||
db, err := NewBoltDB(tmpDir, "test.db", sessDB, clock)
|
||||
db, err := NewBoltDB(tmpDir, "test.db", sessDB, nil, clock)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = db.Close()
|
||||
|
|
@ -452,7 +466,7 @@ func TestListGroupActions(t *testing.T) {
|
|||
State: ActionStateInit,
|
||||
}
|
||||
|
||||
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, clock)
|
||||
db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, nil, clock)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = db.Close()
|
||||
|
|
@ -490,6 +504,9 @@ func TestListGroupActions(t *testing.T) {
|
|||
}
|
||||
|
||||
func assertEqualActions(t *testing.T, expected, got *Action) {
|
||||
// Accounts are not explicitly linked in our bbolt DB implementation.
|
||||
got.AccountID = expected.AccountID
|
||||
|
||||
expectedAttemptedAt := expected.AttemptedAt
|
||||
actualAttemptedAt := got.AttemptedAt
|
||||
|
||||
|
|
@ -501,4 +518,6 @@ func assertEqualActions(t *testing.T, expected, got *Action) {
|
|||
|
||||
expected.AttemptedAt = expectedAttemptedAt
|
||||
got.AttemptedAt = actualAttemptedAt
|
||||
|
||||
got.AccountID = fn.None[accounts.AccountID]()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package firewalldb
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/accounts"
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
)
|
||||
|
||||
|
|
@ -15,6 +16,15 @@ type SessionDB interface {
|
|||
GetSession(context.Context, session.ID) (*session.Session, error)
|
||||
}
|
||||
|
||||
// AccountsDB is an interface that abstracts the database operations needed
|
||||
// firewalldb to be able to query the accounts database.
|
||||
type AccountsDB interface {
|
||||
// Account fetches the Account with the given id from the accounts
|
||||
// database.
|
||||
Account(ctx context.Context,
|
||||
id accounts.AccountID) (*accounts.OffChainBalanceAccount, error)
|
||||
}
|
||||
|
||||
// DBExecutor provides an Update and View method that will allow the caller
|
||||
// to perform atomic read and write transactions defined by PrivacyMapTx on the
|
||||
// underlying BoltDB.
|
||||
|
|
|
|||
|
|
@ -41,12 +41,13 @@ type BoltDB struct {
|
|||
clock clock.Clock
|
||||
|
||||
sessionIDIndex SessionDB
|
||||
accountsDB AccountsDB
|
||||
}
|
||||
|
||||
// NewBoltDB creates a new bolt database that can be found at the given
|
||||
// directory.
|
||||
func NewBoltDB(dir, fileName string, sessionIDIndex SessionDB,
|
||||
clock clock.Clock) (*BoltDB, error) {
|
||||
accountsDB AccountsDB, clock clock.Clock) (*BoltDB, error) {
|
||||
|
||||
firstInit := false
|
||||
path := filepath.Join(dir, fileName)
|
||||
|
|
@ -73,6 +74,7 @@ func NewBoltDB(dir, fileName string, sessionIDIndex SessionDB,
|
|||
return &BoltDB{
|
||||
DB: db,
|
||||
sessionIDIndex: sessionIDIndex,
|
||||
accountsDB: accountsDB,
|
||||
clock: clock,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ package firewalldb
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -18,21 +17,21 @@ func NewTestDB(t *testing.T, clock clock.Clock) *BoltDB {
|
|||
// NewTestDBFromPath is a helper function that creates a new BoltStore with a
|
||||
// connection to an existing BBolt database for testing.
|
||||
func NewTestDBFromPath(t *testing.T, dbPath string, clock clock.Clock) *BoltDB {
|
||||
return newDBFromPathWithSessions(t, dbPath, nil, clock)
|
||||
return newDBFromPathWithSessions(t, dbPath, nil, nil, clock)
|
||||
}
|
||||
|
||||
// NewTestDBWithSessions creates a new test BoltDB Store with access to an
|
||||
// existing sessions DB.
|
||||
func NewTestDBWithSessions(t *testing.T, sessStore session.Store,
|
||||
func NewTestDBWithSessions(t *testing.T, sessStore SessionDB,
|
||||
clock clock.Clock) *BoltDB {
|
||||
|
||||
return newDBFromPathWithSessions(t, t.TempDir(), sessStore, clock)
|
||||
return newDBFromPathWithSessions(t, t.TempDir(), sessStore, nil, clock)
|
||||
}
|
||||
|
||||
func newDBFromPathWithSessions(t *testing.T, dbPath string,
|
||||
sessStore session.Store, clock clock.Clock) *BoltDB {
|
||||
sessStore SessionDB, acctStore AccountsDB, clock clock.Clock) *BoltDB {
|
||||
|
||||
store, err := NewBoltDB(dbPath, DBFilename, sessStore, clock)
|
||||
store, err := NewBoltDB(dbPath, DBFilename, sessStore, acctStore, clock)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue