wtdb+wtclient: segregate session-key-index reservations by blob-type

This commit introduces a change in the key format used to reserve/lookup
session-key-indexes. Currently the reservations are stored under the
tower id, however this creates issues when multiple clients are using
the same database since only one reservation is permitted per tower.

We fix this by appending the blob type to the session-key-index locator.
This allows multiple clients to reserve keys for the same tower, but
still limits each client to one outstanding reservation. The changes are
made in a way such that we fall back to the legacy format if the a
reservation under the new format is not found, but only if the blob type
matches blob.TypeAltruistCommit, which is so far the only actively
deployed blob type.
This commit is contained in:
Conner Fromknecht committed 2020-12-01 16:24:16 -08:00
1 parent 7f330d79c1
commit 9bd73c0a85
5 files changed
+161 -39

No files matched your search

+47 -10
View File
@@ -7,11 +7,17 @@ import (
"github.com/btcsuite/btcd/btcec"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/watchtower/blob"
"github.com/lightningnetwork/lnd/watchtower/wtdb"
)
type towerPK [33]byte
type keyIndexKey struct {
towerID wtdb.TowerID
blobType blob.Type
}
// ClientDB is a mock, in-memory database or testing the watchtower client
// behavior.
type ClientDB struct {
@@ -23,8 +29,9 @@ type ClientDB struct {
towerIndex map[towerPK]wtdb.TowerID
towers map[wtdb.TowerID]*wtdb.Tower
nextIndex uint32
indexes map[wtdb.TowerID]uint32
nextIndex uint32
indexes map[keyIndexKey]uint32
legacyIndexes map[wtdb.TowerID]uint32
}
// NewClientDB initializes a new mock ClientDB.
@@ -34,7 +41,8 @@ func NewClientDB() *ClientDB {
activeSessions: make(map[wtdb.SessionID]wtdb.ClientSession),
towerIndex: make(map[towerPK]wtdb.TowerID),
towers: make(map[wtdb.TowerID]*wtdb.Tower),
indexes: make(map[wtdb.TowerID]uint32),
indexes: make(map[keyIndexKey]uint32),
legacyIndexes: make(map[wtdb.TowerID]uint32),
}
}
@@ -229,10 +237,15 @@ func (m *ClientDB) CreateClientSession(session *wtdb.ClientSession) error {
return wtdb.ErrClientSessionAlreadyExists
}
key := keyIndexKey{
towerID: session.TowerID,
blobType: session.Policy.BlobType,
}
// Ensure that a session key index has been reserved for this tower.
keyIndex, ok := m.indexes[session.TowerID]
if !ok {
return wtdb.ErrNoReservedKeyIndex
keyIndex, err := m.getSessionKeyIndex(key)
if err != nil {
return err
}
// Ensure that the session's index matches the reserved index.
@@ -242,7 +255,10 @@ func (m *ClientDB) CreateClientSession(session *wtdb.ClientSession) error {
// Remove the key index reservation for this tower. Once committed, this
// permits us to create another session with this tower.
delete(m.indexes, session.TowerID)
delete(m.indexes, key)
if key.blobType == blob.TypeAltruistCommit {
delete(m.legacyIndexes, key.towerID)
}
m.activeSessions[session.ID] = wtdb.ClientSession{
ID: session.ID,
@@ -266,21 +282,42 @@ func (m *ClientDB) CreateClientSession(session *wtdb.ClientSession) error {
// CreateClientSession is invoked for that tower and index, at which point a new
// index for that tower can be reserved. Multiple calls to this method before
// CreateClientSession is invoked should return the same index.
func (m *ClientDB) NextSessionKeyIndex(towerID wtdb.TowerID) (uint32, error) {
func (m *ClientDB) NextSessionKeyIndex(towerID wtdb.TowerID,
blobType blob.Type) (uint32, error) {
m.mu.Lock()
defer m.mu.Unlock()
if index, ok := m.indexes[towerID]; ok {
key := keyIndexKey{
towerID: towerID,
blobType: blobType,
}
if index, err := m.getSessionKeyIndex(key); err == nil {
return index, nil
}
m.nextIndex++
index := m.nextIndex
m.indexes[towerID] = index
m.indexes[key] = index
return index, nil
}
func (m *ClientDB) getSessionKeyIndex(key keyIndexKey) (uint32, error) {
if index, ok := m.indexes[key]; ok {
return index, nil
}
if key.blobType == blob.TypeAltruistCommit {
if index, ok := m.legacyIndexes[key.towerID]; ok {
return index, nil
}
}
return 0, wtdb.ErrNoReservedKeyIndex
}
// CommitUpdate persists the CommittedUpdate provided in the slot for (session,
// seqNum). This allows the client to retransmit this update on startup.
func (m *ClientDB) CommitUpdate(id *wtdb.SessionID,