mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-27 22:21:18 +02:00
watchtower/wtmock/tower_db: move mock tower db to wtmock pkg
This commit is contained in:
162
watchtower/wtmock/tower_db.go
Normal file
162
watchtower/wtmock/tower_db.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package wtmock
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||
)
|
||||
|
||||
// TowerDB is a mock, in-memory implementation of a watchtower.DB.
|
||||
type TowerDB struct {
|
||||
mu sync.Mutex
|
||||
lastEpoch *chainntnfs.BlockEpoch
|
||||
sessions map[wtdb.SessionID]*wtdb.SessionInfo
|
||||
blobs map[wtdb.BreachHint]map[wtdb.SessionID]*wtdb.SessionStateUpdate
|
||||
}
|
||||
|
||||
// NewTowerDB initializes a fresh mock TowerDB.
|
||||
func NewTowerDB() *TowerDB {
|
||||
return &TowerDB{
|
||||
sessions: make(map[wtdb.SessionID]*wtdb.SessionInfo),
|
||||
blobs: make(map[wtdb.BreachHint]map[wtdb.SessionID]*wtdb.SessionStateUpdate),
|
||||
}
|
||||
}
|
||||
|
||||
// InsertStateUpdate stores an update sent by the client after validating that
|
||||
// the update is well-formed in the context of other updates sent for the same
|
||||
// session. This include verifying that the sequence number is incremented
|
||||
// properly and the last applied values echoed by the client are sane.
|
||||
func (db *TowerDB) InsertStateUpdate(update *wtdb.SessionStateUpdate) (uint16, error) {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
info, ok := db.sessions[update.ID]
|
||||
if !ok {
|
||||
return 0, wtdb.ErrSessionNotFound
|
||||
}
|
||||
|
||||
err := info.AcceptUpdateSequence(update.SeqNum, update.LastApplied)
|
||||
if err != nil {
|
||||
return info.LastApplied, err
|
||||
}
|
||||
|
||||
sessionsToUpdates, ok := db.blobs[update.Hint]
|
||||
if !ok {
|
||||
sessionsToUpdates = make(map[wtdb.SessionID]*wtdb.SessionStateUpdate)
|
||||
db.blobs[update.Hint] = sessionsToUpdates
|
||||
}
|
||||
sessionsToUpdates[update.ID] = update
|
||||
|
||||
return info.LastApplied, nil
|
||||
}
|
||||
|
||||
// GetSessionInfo retrieves the session for the passed session id. An error is
|
||||
// returned if the session could not be found.
|
||||
func (db *TowerDB) GetSessionInfo(id *wtdb.SessionID) (*wtdb.SessionInfo, error) {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
if info, ok := db.sessions[*id]; ok {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
return nil, wtdb.ErrSessionNotFound
|
||||
}
|
||||
|
||||
// InsertSessionInfo records a negotiated session in the tower database. An
|
||||
// error is returned if the session already exists.
|
||||
func (db *TowerDB) InsertSessionInfo(info *wtdb.SessionInfo) error {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
dbInfo, ok := db.sessions[info.ID]
|
||||
if ok && dbInfo.LastApplied > 0 {
|
||||
return wtdb.ErrSessionAlreadyExists
|
||||
}
|
||||
|
||||
db.sessions[info.ID] = info
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSession removes all data associated with a particular session id from
|
||||
// the tower's database.
|
||||
func (db *TowerDB) DeleteSession(target wtdb.SessionID) error {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
// Fail if the session doesn't exit.
|
||||
if _, ok := db.sessions[target]; !ok {
|
||||
return wtdb.ErrSessionNotFound
|
||||
}
|
||||
|
||||
// Remove the target session.
|
||||
delete(db.sessions, target)
|
||||
|
||||
// Remove the state updates for any blobs stored under the target
|
||||
// session identifier.
|
||||
for hint, sessionUpdates := range db.blobs {
|
||||
delete(sessionUpdates, target)
|
||||
|
||||
// If this was the last state update, we can also remove the
|
||||
// hint that would map to an empty set.
|
||||
if len(sessionUpdates) == 0 {
|
||||
delete(db.blobs, hint)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueryMatches searches against all known state updates for any that match the
|
||||
// passed breachHints. More than one Match will be returned for a given hint if
|
||||
// they exist in the database.
|
||||
func (db *TowerDB) QueryMatches(
|
||||
breachHints []wtdb.BreachHint) ([]wtdb.Match, error) {
|
||||
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
var matches []wtdb.Match
|
||||
for _, hint := range breachHints {
|
||||
sessionsToUpdates, ok := db.blobs[hint]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for id, update := range sessionsToUpdates {
|
||||
info, ok := db.sessions[id]
|
||||
if !ok {
|
||||
panic("session not found")
|
||||
}
|
||||
|
||||
match := wtdb.Match{
|
||||
ID: id,
|
||||
SeqNum: update.SeqNum,
|
||||
Hint: hint,
|
||||
EncryptedBlob: update.EncryptedBlob,
|
||||
SessionInfo: info,
|
||||
}
|
||||
matches = append(matches, match)
|
||||
}
|
||||
}
|
||||
|
||||
return matches, nil
|
||||
}
|
||||
|
||||
// SetLookoutTip stores the provided epoch as the latest lookout tip epoch in
|
||||
// the tower database.
|
||||
func (db *TowerDB) SetLookoutTip(epoch *chainntnfs.BlockEpoch) error {
|
||||
db.lastEpoch = epoch
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLookoutTip retrieves the current lookout tip block epoch from the tower
|
||||
// database.
|
||||
func (db *TowerDB) GetLookoutTip() (*chainntnfs.BlockEpoch, error) {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
return db.lastEpoch, nil
|
||||
}
|
Reference in New Issue
Block a user