wtdb: add a DeactivateTower method
This new method sets the tower's status to inactive so that it is not loaded at startup as a candidate tower. We also ensure that a tower's status is set to active if the CreateTower is called when the tower already exists.
This commit is contained in:
3 files changed
+159
-5
No files matched your search
@@ -140,6 +140,11 @@ type DB interface {
|
|||||||
// DeleteCommittedUpdates deletes all the committed updates belonging to
|
// DeleteCommittedUpdates deletes all the committed updates belonging to
|
||||||
// the given session from the db.
|
// the given session from the db.
|
||||||
DeleteCommittedUpdates(id *wtdb.SessionID) error
|
DeleteCommittedUpdates(id *wtdb.SessionID) error
|
||||||
|
|
||||||
|
// DeactivateTower sets the given tower's status to inactive. This means
|
||||||
|
// that this tower's sessions won't be loaded and used for backups.
|
||||||
|
// CreateTower can be used to reactivate the tower again.
|
||||||
|
DeactivateTower(pubKey *btcec.PublicKey) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthDialer connects to a remote node using an authenticated transport, such
|
// AuthDialer connects to a remote node using an authenticated transport, such
|
||||||
|
|||||||
@@ -387,6 +387,9 @@ func (c *ClientDB) CreateTower(lnAddr *lnwire.NetAddress) (*Tower, error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set its status to active.
|
||||||
|
tower.Status = TowerStatusActive
|
||||||
|
|
||||||
// Add the new address to the existing tower. If the
|
// Add the new address to the existing tower. If the
|
||||||
// address is a duplicate, this will result in no
|
// address is a duplicate, this will result in no
|
||||||
// change.
|
// change.
|
||||||
@@ -503,14 +506,14 @@ func (c *ClientDB) RemoveTower(pubKey *btcec.PublicKey, addr net.Addr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tower, err := getTower(towers, towerIDBytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// If an address is provided, then we should _only_ remove the
|
// If an address is provided, then we should _only_ remove the
|
||||||
// address record from the database.
|
// address record from the database.
|
||||||
if addr != nil {
|
if addr != nil {
|
||||||
tower, err := getTower(towers, towerIDBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Towers should always have at least one address saved.
|
// Towers should always have at least one address saved.
|
||||||
tower.RemoveAddress(addr)
|
tower.RemoveAddress(addr)
|
||||||
if len(tower.Addresses) == 0 {
|
if len(tower.Addresses) == 0 {
|
||||||
@@ -560,6 +563,13 @@ func (c *ClientDB) RemoveTower(pubKey *btcec.PublicKey, addr net.Addr) error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, we mark the tower as inactive.
|
||||||
|
tower.Status = TowerStatusInactive
|
||||||
|
err = putTower(towers, tower)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// We'll mark its sessions as inactive as long as they don't
|
// We'll mark its sessions as inactive as long as they don't
|
||||||
// have any pending updates to ensure we don't load them upon
|
// have any pending updates to ensure we don't load them upon
|
||||||
// restarts.
|
// restarts.
|
||||||
@@ -579,6 +589,57 @@ func (c *ClientDB) RemoveTower(pubKey *btcec.PublicKey, addr net.Addr) error {
|
|||||||
}, func() {})
|
}, func() {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeactivateTower sets the given tower's status to inactive. This means that
|
||||||
|
// this tower's sessions won't be loaded and used for backups. CreateTower can
|
||||||
|
// be used to reactivate the tower again.
|
||||||
|
func (c *ClientDB) DeactivateTower(pubKey *btcec.PublicKey) error {
|
||||||
|
return kvdb.Update(c.db, func(tx kvdb.RwTx) error {
|
||||||
|
towers := tx.ReadWriteBucket(cTowerBkt)
|
||||||
|
if towers == nil {
|
||||||
|
return ErrUninitializedDB
|
||||||
|
}
|
||||||
|
|
||||||
|
towerIndex := tx.ReadWriteBucket(cTowerIndexBkt)
|
||||||
|
if towerIndex == nil {
|
||||||
|
return ErrUninitializedDB
|
||||||
|
}
|
||||||
|
|
||||||
|
towersToSessionsIndex := tx.ReadWriteBucket(
|
||||||
|
cTowerToSessionIndexBkt,
|
||||||
|
)
|
||||||
|
if towersToSessionsIndex == nil {
|
||||||
|
return ErrUninitializedDB
|
||||||
|
}
|
||||||
|
|
||||||
|
chanIDIndexBkt := tx.ReadBucket(cChanIDIndexBkt)
|
||||||
|
if chanIDIndexBkt == nil {
|
||||||
|
return ErrUninitializedDB
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKeyBytes := pubKey.SerializeCompressed()
|
||||||
|
towerIDBytes := towerIndex.Get(pubKeyBytes)
|
||||||
|
if towerIDBytes == nil {
|
||||||
|
return ErrTowerNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
tower, err := getTower(towers, towerIDBytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the tower already has the desired status, then we can exit
|
||||||
|
// here.
|
||||||
|
if tower.Status == TowerStatusInactive {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we update the status and re-store the tower.
|
||||||
|
tower.Status = TowerStatusInactive
|
||||||
|
|
||||||
|
return putTower(towers, tower)
|
||||||
|
}, func() {})
|
||||||
|
}
|
||||||
|
|
||||||
// LoadTowerByID retrieves a tower by its tower ID.
|
// LoadTowerByID retrieves a tower by its tower ID.
|
||||||
func (c *ClientDB) LoadTowerByID(towerID TowerID) (*Tower, error) {
|
func (c *ClientDB) LoadTowerByID(towerID TowerID) (*Tower, error) {
|
||||||
var tower *Tower
|
var tower *Tower
|
||||||
|
|||||||
@@ -89,6 +89,26 @@ func (h *clientDBHarness) createTower(lnAddr *lnwire.NetAddress,
|
|||||||
return tower
|
return tower
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *clientDBHarness) deactivateTower(pubKey *btcec.PublicKey,
|
||||||
|
expErr error) {
|
||||||
|
|
||||||
|
h.t.Helper()
|
||||||
|
|
||||||
|
err := h.db.DeactivateTower(pubKey)
|
||||||
|
require.ErrorIs(h.t, err, expErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *clientDBHarness) listTowers(filterFn wtdb.TowerFilterFn,
|
||||||
|
expErr error) []*wtdb.Tower {
|
||||||
|
|
||||||
|
h.t.Helper()
|
||||||
|
|
||||||
|
towers, err := h.db.ListTowers(filterFn)
|
||||||
|
require.ErrorIs(h.t, err, expErr)
|
||||||
|
|
||||||
|
return towers
|
||||||
|
}
|
||||||
|
|
||||||
func (h *clientDBHarness) removeTower(pubKey *btcec.PublicKey, addr net.Addr,
|
func (h *clientDBHarness) removeTower(pubKey *btcec.PublicKey, addr net.Addr,
|
||||||
hasSessions bool, expErr error) {
|
hasSessions bool, expErr error) {
|
||||||
|
|
||||||
@@ -547,6 +567,70 @@ func testRemoveTower(h *clientDBHarness) {
|
|||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testTowerStatusChange tests that the Tower status is updated accordingly
|
||||||
|
// given a variety of commands.
|
||||||
|
func testTowerStatusChange(h *clientDBHarness) {
|
||||||
|
// Create a new tower.
|
||||||
|
pk, err := randPubKey()
|
||||||
|
require.NoError(h.t, err)
|
||||||
|
|
||||||
|
towerAddr := &lnwire.NetAddress{
|
||||||
|
IdentityKey: pk,
|
||||||
|
Address: &net.TCPAddr{
|
||||||
|
IP: []byte{0x01, 0x00, 0x00, 0x00}, Port: 9911,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tower := h.createTower(towerAddr, nil)
|
||||||
|
|
||||||
|
// Add a new session.
|
||||||
|
session := h.randSession(h.t, tower.ID, 100)
|
||||||
|
h.insertSession(session, nil)
|
||||||
|
|
||||||
|
// assertTowerStatus is a helper function that will assert that the
|
||||||
|
// tower's status is as expected.
|
||||||
|
assertTowerStatus := func(status wtdb.TowerStatus) {
|
||||||
|
activeFilter := func(tower *wtdb.Tower) bool {
|
||||||
|
return tower.Status == status
|
||||||
|
}
|
||||||
|
|
||||||
|
towers := h.listTowers(activeFilter, nil)
|
||||||
|
require.Len(h.t, towers, 1)
|
||||||
|
require.EqualValues(h.t, towers[0].Status, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertSessionStatus is a helper that will assert that the session's
|
||||||
|
// status is as expected
|
||||||
|
assertSessionStatus := func(status wtdb.CSessionStatus) {
|
||||||
|
sessions := h.listSessions(&tower.ID)
|
||||||
|
require.Len(h.t, sessions, 1)
|
||||||
|
for _, sess := range sessions {
|
||||||
|
require.EqualValues(h.t, sess.Status, status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initially, the tower and session should be active.
|
||||||
|
assertTowerStatus(wtdb.TowerStatusActive)
|
||||||
|
assertSessionStatus(wtdb.CSessionActive)
|
||||||
|
|
||||||
|
// Removing the tower should change its status and its session status
|
||||||
|
// to inactive.
|
||||||
|
h.removeTower(tower.IdentityKey, nil, true, nil)
|
||||||
|
assertTowerStatus(wtdb.TowerStatusInactive)
|
||||||
|
assertSessionStatus(wtdb.CSessionInactive)
|
||||||
|
|
||||||
|
// Re-adding the tower in some way should re-active it and its session.
|
||||||
|
h.createTower(towerAddr, nil)
|
||||||
|
assertTowerStatus(wtdb.TowerStatusActive)
|
||||||
|
assertSessionStatus(wtdb.CSessionActive)
|
||||||
|
|
||||||
|
// Deactivating the tower should change its status but its session
|
||||||
|
// status should remain active.
|
||||||
|
h.deactivateTower(tower.IdentityKey, nil)
|
||||||
|
assertTowerStatus(wtdb.TowerStatusInactive)
|
||||||
|
assertSessionStatus(wtdb.CSessionActive)
|
||||||
|
}
|
||||||
|
|
||||||
// testChanSummaries tests the process of a registering a channel and its
|
// testChanSummaries tests the process of a registering a channel and its
|
||||||
// associated sweep pkscript.
|
// associated sweep pkscript.
|
||||||
func testChanSummaries(h *clientDBHarness) {
|
func testChanSummaries(h *clientDBHarness) {
|
||||||
@@ -1142,6 +1226,10 @@ func TestClientDB(t *testing.T) {
|
|||||||
name: "max commitment heights",
|
name: "max commitment heights",
|
||||||
run: testMaxCommitmentHeights,
|
run: testMaxCommitmentHeights,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "test tower status change",
|
||||||
|
run: testTowerStatusChange,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, database := range dbs {
|
for _, database := range dbs {
|
||||||
|
|||||||
Reference in new issue
Block a user