diff --git a/accounts/interceptor.go b/accounts/interceptor.go index 56e9908e9..5ca331b24 100644 --- a/accounts/interceptor.go +++ b/accounts/interceptor.go @@ -81,7 +81,7 @@ func (s *InterceptorService) Intercept(ctx context.Context, return mid.RPCErrString(req, "error parsing macaroon: %v", err) } - acctID, err := accountFromMacaroon(mac) + acctID, err := IDFromCaveats(mac.Caveats()) if err != nil { return mid.RPCErrString( req, "error parsing account from macaroon: %v", err, @@ -91,15 +91,17 @@ func (s *InterceptorService) Intercept(ctx context.Context, // No account lock in the macaroon, something's weird. The interceptor // wouldn't have been triggered if there was no caveat, so we do expect // a macaroon here. - if acctID == nil { - return mid.RPCErrString(req, "expected account ID in "+ - "macaroon caveat") + accountID, err := acctID.UnwrapOrErr( + fmt.Errorf("expected account ID in macaroon caveat"), + ) + if err != nil { + return mid.RPCErr(req, err) } - acct, err := s.Account(ctx, *acctID) + acct, err := s.Account(ctx, accountID) if err != nil { return mid.RPCErrString( - req, "error getting account %x: %v", acctID[:], err, + req, "error getting account %x: %v", accountID[:], err, ) } @@ -208,27 +210,6 @@ func parseRPCMessage(msg *lnrpc.RPCMessage) (proto.Message, error) { return parsedMsg, nil } -// accountFromMacaroon attempts to extract an account ID from the custom account -// caveat in the macaroon. -func accountFromMacaroon(mac *macaroon.Macaroon) (*AccountID, error) { - if mac == nil { - return nil, nil - } - - // Extract the account caveat from the macaroon. - accountID, err := IDFromCaveats(mac.Caveats()) - if err != nil { - return nil, err - } - - var id *AccountID - accountID.WhenSome(func(aID AccountID) { - id = &aID - }) - - return id, nil -} - // CaveatFromID creates a custom caveat that can be used to bind a macaroon to // a certain account. func CaveatFromID(id AccountID) macaroon.Caveat { diff --git a/config_dev.go b/config_dev.go index ae7d18977..4ab17bd77 100644 --- a/config_dev.go +++ b/config_dev.go @@ -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", diff --git a/config_prod.go b/config_prod.go index 5ea897fc8..c13d66960 100644 --- a/config_prod.go +++ b/config_prod.go @@ -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) diff --git a/firewall/request_info.go b/firewall/request_info.go index fd312b71f..3036071da 100644 --- a/firewall/request_info.go +++ b/firewall/request_info.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/lightninglabs/lightning-terminal/accounts" "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/lnrpc" @@ -29,6 +30,7 @@ const ( // request. type RequestInfo struct { SessionID fn.Option[session.ID] + AccountID fn.Option[accounts.AccountID] MsgID uint64 RequestID uint64 MWRequestType string @@ -140,6 +142,12 @@ func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) { } } + ri.AccountID, err = accounts.IDFromCaveats(ri.Macaroon.Caveats()) + if err != nil { + return nil, fmt.Errorf("error extracting account ID "+ + "from macaroon: %v", err) + } + return ri, nil } diff --git a/firewall/request_logger.go b/firewall/request_logger.go index 0a98e6458..8b038a6b6 100644 --- a/firewall/request_logger.go +++ b/firewall/request_logger.go @@ -195,6 +195,7 @@ func (r *RequestLogger) addNewAction(ctx context.Context, ri *RequestInfo, actionReq := &firewalldb.AddActionReq{ SessionID: ri.SessionID, + AccountID: ri.AccountID, MacaroonIdentifier: macaroonID, RPCMethod: ri.URI, } diff --git a/firewalldb/actions.go b/firewalldb/actions.go index 129913a19..88172e31b 100644 --- a/firewalldb/actions.go +++ b/firewalldb/actions.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/lightninglabs/lightning-terminal/accounts" "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/fn" ) @@ -45,6 +46,13 @@ type AddActionReq struct { // guaranteed to be linked to an existing session. SessionID fn.Option[session.ID] + // AccountID holds the optional account ID of the account that this + // action was performed on. + // + // NOTE: for our BoltDB impl, this is not persisted in any way, and we + // do not populate it on reading from disk. + AccountID fn.Option[accounts.AccountID] + // ActorName is the name of the entity who performed the Action. ActorName string diff --git a/firewalldb/actions_kvdb.go b/firewalldb/actions_kvdb.go index f2b20465f..7a8ae3e15 100644 --- a/firewalldb/actions_kvdb.go +++ b/firewalldb/actions_kvdb.go @@ -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" @@ -54,9 +55,32 @@ var ( ) // AddAction serialises and adds an Action to the DB under the given sessionID. -func (db *BoltDB) AddAction(_ context.Context, +func (db *BoltDB) AddAction(ctx context.Context, req *AddActionReq) (ActionLocator, error) { + // If the new action links to a session, the session must exist. + // For the bbolt impl of the store, this is our best effort attempt + // at ensuring each action links to a session. If the session is + // deleted later on, however, then the action will still exist. + var err error + req.SessionID.WhenSome(func(id session.ID) { + _, err = db.sessionIDIndex.GetSession(ctx, id) + }) + if err != nil { + 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(), @@ -69,7 +93,7 @@ func (db *BoltDB) AddAction(_ context.Context, } var locator kvdbActionLocator - err := db.DB.Update(func(tx *bbolt.Tx) error { + err = db.DB.Update(func(tx *bbolt.Tx) error { mainActionsBucket, err := getBucket(tx, actionsBucketKey) if err != nil { return err diff --git a/firewalldb/actions_test.go b/firewalldb/actions_test.go index 12824ff39..0f93ed2fe 100644 --- a/firewalldb/actions_test.go +++ b/firewalldb/actions_test.go @@ -6,6 +6,8 @@ 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" "github.com/stretchr/testify/require" @@ -22,17 +24,50 @@ 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", nil, clock) + db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, accountsDB, clock) require.NoError(t, err) t.Cleanup(func() { _ = db.Close() }) - sessionID1 := intToSessionID(1) + // Assert that attempting to add an action for a session that does not + // exist returns an error. + _, err = db.AddAction(ctx, &AddActionReq{ + SessionID: fn.Some(session.ID{1, 2, 3, 4}), + }) + 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), + "something", + ) + require.NoError(t, err) + + sess2, err := sessDB.NewSession( + ctx, "sess 2", session.TypeAutopilot, time.Unix(1000, 0), + "something", + ) + 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(sessionID1), - MacaroonIdentifier: sessionID1, + SessionID: fn.Some(sess1.ID), + AccountID: fn.Some(acct1.ID), + MacaroonIdentifier: sess1.ID, ActorName: "Autopilot", FeatureName: "auto-fees", Trigger: "fee too low", @@ -48,10 +83,9 @@ func TestActionStorage(t *testing.T) { State: ActionStateDone, } - sessionID2 := intToSessionID(2) action2Req := &AddActionReq{ - SessionID: fn.Some(sessionID2), - MacaroonIdentifier: sessionID2, + SessionID: fn.Some(sess2.ID), + MacaroonIdentifier: sess2.ID, ActorName: "Autopilot", FeatureName: "rebalancer", Trigger: "channels not balanced", @@ -68,7 +102,7 @@ func TestActionStorage(t *testing.T) { actions, _, _, err := db.ListActions( ctx, nil, - WithActionSessionID(sessionID1), + WithActionSessionID(sess1.ID), WithActionState(ActionStateDone), ) require.NoError(t, err) @@ -76,7 +110,7 @@ func TestActionStorage(t *testing.T) { actions, _, _, err = db.ListActions( ctx, nil, - WithActionSessionID(sessionID2), + WithActionSessionID(sess2.ID), WithActionState(ActionStateDone), ) require.NoError(t, err) @@ -94,7 +128,7 @@ func TestActionStorage(t *testing.T) { actions, _, _, err = db.ListActions( ctx, nil, - WithActionSessionID(sessionID1), + WithActionSessionID(sess1.ID), WithActionState(ActionStateDone), ) require.NoError(t, err) @@ -103,7 +137,7 @@ func TestActionStorage(t *testing.T) { actions, _, _, err = db.ListActions( ctx, nil, - WithActionSessionID(sessionID2), + WithActionSessionID(sess2.ID), WithActionState(ActionStateDone), ) require.NoError(t, err) @@ -114,7 +148,7 @@ func TestActionStorage(t *testing.T) { actions, _, _, err = db.ListActions( ctx, nil, - WithActionSessionID(sessionID2), + WithActionSessionID(sess2.ID), WithActionState(ActionStateDone), ) require.NoError(t, err) @@ -145,7 +179,7 @@ func TestActionStorage(t *testing.T) { actions, _, _, err = db.ListActions( ctx, nil, - WithActionSessionID(sessionID2), + WithActionSessionID(sess2.ID), WithActionState(ActionStateError), ) require.NoError(t, err) @@ -162,15 +196,27 @@ func TestListActions(t *testing.T) { tmpDir := t.TempDir() ctx := context.Background() + clock := clock.NewDefaultClock() + sessDB := session.NewTestDB(t, clock) - db, err := NewBoltDB(tmpDir, "test.db", nil, clock.NewDefaultClock()) + db, err := NewBoltDB(tmpDir, "test.db", sessDB, nil, clock) require.NoError(t, err) t.Cleanup(func() { _ = db.Close() }) - sessionID1 := [4]byte{1, 1, 1, 1} - sessionID2 := [4]byte{2, 2, 2, 2} + // Add 2 sessions that we can reference. + sess1, err := sessDB.NewSession( + ctx, "sess 1", session.TypeAutopilot, time.Unix(1000, 0), + "something", + ) + require.NoError(t, err) + + sess2, err := sessDB.NewSession( + ctx, "sess 2", session.TypeAutopilot, time.Unix(1000, 0), + "nothing", + ) + require.NoError(t, err) actionIds := 0 addAction := func(sessionID [4]byte) { @@ -206,11 +252,11 @@ func TestListActions(t *testing.T) { } } - addAction(sessionID1) - addAction(sessionID1) - addAction(sessionID1) - addAction(sessionID1) - addAction(sessionID2) + addAction(sess1.ID) + addAction(sess1.ID) + addAction(sess1.ID) + addAction(sess1.ID) + addAction(sess2.ID) actions, lastIndex, totalCount, err := db.ListActions(ctx, nil) require.NoError(t, err) @@ -218,11 +264,11 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 5, lastIndex) require.EqualValues(t, 0, totalCount) assertActions(actions, []*action{ - {sessionID1, "1"}, - {sessionID1, "2"}, - {sessionID1, "3"}, - {sessionID1, "4"}, - {sessionID2, "5"}, + {sess1.ID, "1"}, + {sess1.ID, "2"}, + {sess1.ID, "3"}, + {sess1.ID, "4"}, + {sess2.ID, "5"}, }) query := &ListActionsQuery{ @@ -235,11 +281,11 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 1, lastIndex) require.EqualValues(t, 0, totalCount) assertActions(actions, []*action{ - {sessionID2, "5"}, - {sessionID1, "4"}, - {sessionID1, "3"}, - {sessionID1, "2"}, - {sessionID1, "1"}, + {sess2.ID, "5"}, + {sess1.ID, "4"}, + {sess1.ID, "3"}, + {sess1.ID, "2"}, + {sess1.ID, "1"}, }) actions, lastIndex, totalCount, err = db.ListActions( @@ -252,11 +298,11 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 5, lastIndex) require.EqualValues(t, 5, totalCount) assertActions(actions, []*action{ - {sessionID1, "1"}, - {sessionID1, "2"}, - {sessionID1, "3"}, - {sessionID1, "4"}, - {sessionID2, "5"}, + {sess1.ID, "1"}, + {sess1.ID, "2"}, + {sess1.ID, "3"}, + {sess1.ID, "4"}, + {sess2.ID, "5"}, }) actions, lastIndex, totalCount, err = db.ListActions( @@ -270,18 +316,18 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 1, lastIndex) require.EqualValues(t, 5, totalCount) assertActions(actions, []*action{ - {sessionID2, "5"}, - {sessionID1, "4"}, - {sessionID1, "3"}, - {sessionID1, "2"}, - {sessionID1, "1"}, + {sess2.ID, "5"}, + {sess1.ID, "4"}, + {sess1.ID, "3"}, + {sess1.ID, "2"}, + {sess1.ID, "1"}, }) - addAction(sessionID2) - addAction(sessionID2) - addAction(sessionID1) - addAction(sessionID1) - addAction(sessionID2) + addAction(sess2.ID) + addAction(sess2.ID) + addAction(sess1.ID) + addAction(sess1.ID) + addAction(sess2.ID) actions, lastIndex, totalCount, err = db.ListActions(ctx, nil) require.NoError(t, err) @@ -289,16 +335,16 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 10, lastIndex) require.EqualValues(t, 0, totalCount) assertActions(actions, []*action{ - {sessionID1, "1"}, - {sessionID1, "2"}, - {sessionID1, "3"}, - {sessionID1, "4"}, - {sessionID2, "5"}, - {sessionID2, "6"}, - {sessionID2, "7"}, - {sessionID1, "8"}, - {sessionID1, "9"}, - {sessionID2, "10"}, + {sess1.ID, "1"}, + {sess1.ID, "2"}, + {sess1.ID, "3"}, + {sess1.ID, "4"}, + {sess2.ID, "5"}, + {sess2.ID, "6"}, + {sess2.ID, "7"}, + {sess1.ID, "8"}, + {sess1.ID, "9"}, + {sess2.ID, "10"}, }) actions, lastIndex, totalCount, err = db.ListActions( @@ -312,9 +358,9 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 3, lastIndex) require.EqualValues(t, 10, totalCount) assertActions(actions, []*action{ - {sessionID1, "1"}, - {sessionID1, "2"}, - {sessionID1, "3"}, + {sess1.ID, "1"}, + {sess1.ID, "2"}, + {sess1.ID, "3"}, }) actions, lastIndex, totalCount, err = db.ListActions( @@ -328,9 +374,9 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 6, lastIndex) require.EqualValues(t, 0, totalCount) assertActions(actions, []*action{ - {sessionID1, "4"}, - {sessionID2, "5"}, - {sessionID2, "6"}, + {sess1.ID, "4"}, + {sess2.ID, "5"}, + {sess2.ID, "6"}, }) actions, lastIndex, totalCount, err = db.ListActions( @@ -345,9 +391,9 @@ func TestListActions(t *testing.T) { require.EqualValues(t, 6, lastIndex) require.EqualValues(t, 10, totalCount) assertActions(actions, []*action{ - {sessionID1, "4"}, - {sessionID2, "5"}, - {sessionID2, "6"}, + {sess1.ID, "4"}, + {sess2.ID, "5"}, + {sess2.ID, "6"}, }) } @@ -358,12 +404,36 @@ func TestListGroupActions(t *testing.T) { ctx := context.Background() clock := clock.NewTestClock(testTime1) - group1 := intToSessionID(0) + sessDB := session.NewTestDB(t, clock) + + // Create two sessions both linked to session 1's group. + sess1, err := sessDB.NewSession( + ctx, "sess 1", session.TypeAutopilot, time.Unix(1000, 0), + "something", + ) + require.NoError(t, err) + + // We'll first need to revoke session 1 before we can link another + // session to the group. + require.NoError( + t, sessDB.ShiftState(ctx, sess1.ID, session.StateCreated), + ) + require.NoError( + t, sessDB.ShiftState(ctx, sess1.ID, session.StateRevoked), + ) + + group1 := sess1.GroupID + + // Create session 2 and link it to the same group as session 1. + sess2, err := sessDB.NewSession( + ctx, "sess 2", session.TypeAutopilot, time.Unix(1000, 0), + "something", session.WithLinkedGroupID(&group1), + ) + require.NoError(t, err) - sessionID1 := intToSessionID(1) action1Req := &AddActionReq{ - SessionID: fn.Some(sessionID1), - MacaroonIdentifier: sessionID1, + SessionID: fn.Some(sess1.ID), + MacaroonIdentifier: sess1.ID, ActorName: "Autopilot", FeatureName: "auto-fees", Trigger: "fee too low", @@ -379,10 +449,9 @@ func TestListGroupActions(t *testing.T) { State: ActionStateDone, } - sessionID2 := intToSessionID(2) action2Req := &AddActionReq{ - SessionID: fn.Some(sessionID2), - MacaroonIdentifier: sessionID2, + SessionID: fn.Some(sess2.ID), + MacaroonIdentifier: sess2.ID, ActorName: "Autopilot", FeatureName: "rebalancer", Trigger: "channels not balanced", @@ -397,12 +466,7 @@ func TestListGroupActions(t *testing.T) { State: ActionStateInit, } - // Link session 1 and session 2 to group 1. - index := NewMockSessionDB() - index.AddPair(sessionID1, group1) - index.AddPair(sessionID2, group1) - - db, err := NewBoltDB(t.TempDir(), "test.db", index, clock) + db, err := NewBoltDB(t.TempDir(), "test.db", sessDB, nil, clock) require.NoError(t, err) t.Cleanup(func() { _ = db.Close() @@ -440,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 @@ -451,4 +518,6 @@ func assertEqualActions(t *testing.T, expected, got *Action) { expected.AttemptedAt = expectedAttemptedAt got.AttemptedAt = actualAttemptedAt + + got.AccountID = fn.None[accounts.AccountID]() } diff --git a/firewalldb/interface.go b/firewalldb/interface.go index 7da9cf5b0..5ee729e91 100644 --- a/firewalldb/interface.go +++ b/firewalldb/interface.go @@ -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. diff --git a/firewalldb/kvdb_store.go b/firewalldb/kvdb_store.go index edef36a11..e3256e899 100644 --- a/firewalldb/kvdb_store.go +++ b/firewalldb/kvdb_store.go @@ -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 } diff --git a/firewalldb/kvstores_test.go b/firewalldb/kvstores_test.go index 20f6ec0c7..26d2d7c95 100644 --- a/firewalldb/kvstores_test.go +++ b/firewalldb/kvstores_test.go @@ -469,10 +469,3 @@ func TestKVStoreSessionCoupling(t *testing.T) { }) require.NoError(t, err) } - -func intToSessionID(i uint32) session.ID { - var id session.ID - byteOrder.PutUint32(id[:], i) - - return id -} diff --git a/firewalldb/test_kvdb.go b/firewalldb/test_kvdb.go index 2c0ad66c9..659292702 100644 --- a/firewalldb/test_kvdb.go +++ b/firewalldb/test_kvdb.go @@ -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() {