github.com/decred/dcrlnd@v0.7.6/watchtower/wtdb/client_db.go (about)

     1  package wtdb
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"math"
     8  	"net"
     9  
    10  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    11  	"github.com/decred/dcrlnd/kvdb"
    12  	"github.com/decred/dcrlnd/lnwire"
    13  	"github.com/decred/dcrlnd/watchtower/blob"
    14  )
    15  
    16  var (
    17  	// cSessionKeyIndexBkt is a top-level bucket storing:
    18  	//   tower-id -> reserved-session-key-index (uint32).
    19  	cSessionKeyIndexBkt = []byte("client-session-key-index-bucket")
    20  
    21  	// cChanSummaryBkt is a top-level bucket storing:
    22  	//   channel-id -> encoded ClientChanSummary.
    23  	cChanSummaryBkt = []byte("client-channel-summary-bucket")
    24  
    25  	// cSessionBkt is a top-level bucket storing:
    26  	//   session-id => cSessionBody -> encoded ClientSessionBody
    27  	//              => cSessionCommits => seqnum -> encoded CommittedUpdate
    28  	//              => cSessionAcks => seqnum -> encoded BackupID
    29  	cSessionBkt = []byte("client-session-bucket")
    30  
    31  	// cSessionBody is a sub-bucket of cSessionBkt storing only the body of
    32  	// the ClientSession.
    33  	cSessionBody = []byte("client-session-body")
    34  
    35  	// cSessionBody is a sub-bucket of cSessionBkt storing:
    36  	//    seqnum -> encoded CommittedUpdate.
    37  	cSessionCommits = []byte("client-session-commits")
    38  
    39  	// cSessionAcks is a sub-bucket of cSessionBkt storing:
    40  	//    seqnum -> encoded BackupID.
    41  	cSessionAcks = []byte("client-session-acks")
    42  
    43  	// cTowerBkt is a top-level bucket storing:
    44  	//    tower-id -> encoded Tower.
    45  	cTowerBkt = []byte("client-tower-bucket")
    46  
    47  	// cTowerIndexBkt is a top-level bucket storing:
    48  	//    tower-pubkey -> tower-id.
    49  	cTowerIndexBkt = []byte("client-tower-index-bucket")
    50  
    51  	// ErrTowerNotFound signals that the target tower was not found in the
    52  	// database.
    53  	ErrTowerNotFound = errors.New("tower not found")
    54  
    55  	// ErrTowerUnackedUpdates is an error returned when we attempt to mark a
    56  	// tower's sessions as inactive, but one of its sessions has unacked
    57  	// updates.
    58  	ErrTowerUnackedUpdates = errors.New("tower has unacked updates")
    59  
    60  	// ErrCorruptClientSession signals that the client session's on-disk
    61  	// structure deviates from what is expected.
    62  	ErrCorruptClientSession = errors.New("client session corrupted")
    63  
    64  	// ErrClientSessionAlreadyExists signals an attempt to reinsert a client
    65  	// session that has already been created.
    66  	ErrClientSessionAlreadyExists = errors.New(
    67  		"client session already exists",
    68  	)
    69  
    70  	// ErrChannelAlreadyRegistered signals a duplicate attempt to register a
    71  	// channel with the client database.
    72  	ErrChannelAlreadyRegistered = errors.New("channel already registered")
    73  
    74  	// ErrChannelNotRegistered signals a channel has not yet been registered
    75  	// in the client database.
    76  	ErrChannelNotRegistered = errors.New("channel not registered")
    77  
    78  	// ErrClientSessionNotFound signals that the requested client session
    79  	// was not found in the database.
    80  	ErrClientSessionNotFound = errors.New("client session not found")
    81  
    82  	// ErrUpdateAlreadyCommitted signals that the chosen sequence number has
    83  	// already been committed to an update with a different breach hint.
    84  	ErrUpdateAlreadyCommitted = errors.New("update already committed")
    85  
    86  	// ErrCommitUnorderedUpdate signals the client tried to commit a
    87  	// sequence number other than the next unallocated sequence number.
    88  	ErrCommitUnorderedUpdate = errors.New("update seqnum not monotonic")
    89  
    90  	// ErrCommittedUpdateNotFound signals that the tower tried to ACK a
    91  	// sequence number that has not yet been allocated by the client.
    92  	ErrCommittedUpdateNotFound = errors.New("committed update not found")
    93  
    94  	// ErrUnallocatedLastApplied signals that the tower tried to provide a
    95  	// LastApplied value greater than any allocated sequence number.
    96  	ErrUnallocatedLastApplied = errors.New("tower echoed last appiled " +
    97  		"greater than allocated seqnum")
    98  
    99  	// ErrNoReservedKeyIndex signals that a client session could not be
   100  	// created because no session key index was reserved.
   101  	ErrNoReservedKeyIndex = errors.New("key index not reserved")
   102  
   103  	// ErrIncorrectKeyIndex signals that the client session could not be
   104  	// created because session key index differs from the reserved key
   105  	// index.
   106  	ErrIncorrectKeyIndex = errors.New("incorrect key index")
   107  
   108  	// ErrLastTowerAddr is an error returned when the last address of a
   109  	// watchtower is attempted to be removed.
   110  	ErrLastTowerAddr = errors.New("cannot remove last tower address")
   111  )
   112  
   113  // NewBoltBackendCreator returns a function that creates a new bbolt backend for
   114  // the watchtower database.
   115  func NewBoltBackendCreator(active bool, dbPath,
   116  	dbFileName string) func(boltCfg *kvdb.BoltConfig) (kvdb.Backend, error) {
   117  
   118  	// If the watchtower client isn't active, we return a function that
   119  	// always returns a nil DB to make sure we don't create empty database
   120  	// files.
   121  	if !active {
   122  		return func(_ *kvdb.BoltConfig) (kvdb.Backend, error) {
   123  			return nil, nil
   124  		}
   125  	}
   126  
   127  	return func(boltCfg *kvdb.BoltConfig) (kvdb.Backend, error) {
   128  		cfg := &kvdb.BoltBackendConfig{
   129  			DBPath:            dbPath,
   130  			DBFileName:        dbFileName,
   131  			NoFreelistSync:    boltCfg.NoFreelistSync,
   132  			AutoCompact:       boltCfg.AutoCompact,
   133  			AutoCompactMinAge: boltCfg.AutoCompactMinAge,
   134  			DBTimeout:         boltCfg.DBTimeout,
   135  		}
   136  
   137  		db, err := kvdb.GetBoltBackend(cfg)
   138  		if err != nil {
   139  			return nil, fmt.Errorf("could not open boltdb: %v", err)
   140  		}
   141  
   142  		return db, nil
   143  	}
   144  }
   145  
   146  // ClientDB is single database providing a persistent storage engine for the
   147  // wtclient.
   148  type ClientDB struct {
   149  	db kvdb.Backend
   150  }
   151  
   152  // OpenClientDB opens the client database given the path to the database's
   153  // directory. If no such database exists, this method will initialize a fresh
   154  // one using the latest version number and bucket structure. If a database
   155  // exists but has a lower version number than the current version, any necessary
   156  // migrations will be applied before returning. Any attempt to open a database
   157  // with a version number higher that the latest version will fail to prevent
   158  // accidental reversion.
   159  func OpenClientDB(db kvdb.Backend) (*ClientDB, error) {
   160  	firstInit, err := isFirstInit(db)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	clientDB := &ClientDB{
   166  		db: db,
   167  	}
   168  
   169  	err = initOrSyncVersions(clientDB, firstInit, clientDBVersions)
   170  	if err != nil {
   171  		db.Close()
   172  		return nil, err
   173  	}
   174  
   175  	// Now that the database version fully consistent with our latest known
   176  	// version, ensure that all top-level buckets known to this version are
   177  	// initialized. This allows us to assume their presence throughout all
   178  	// operations. If an known top-level bucket is expected to exist but is
   179  	// missing, this will trigger a ErrUninitializedDB error.
   180  	err = kvdb.Update(clientDB.db, initClientDBBuckets, func() {})
   181  	if err != nil {
   182  		db.Close()
   183  		return nil, err
   184  	}
   185  
   186  	return clientDB, nil
   187  }
   188  
   189  // initClientDBBuckets creates all top-level buckets required to handle database
   190  // operations required by the latest version.
   191  func initClientDBBuckets(tx kvdb.RwTx) error {
   192  	buckets := [][]byte{
   193  		cSessionKeyIndexBkt,
   194  		cChanSummaryBkt,
   195  		cSessionBkt,
   196  		cTowerBkt,
   197  		cTowerIndexBkt,
   198  	}
   199  
   200  	for _, bucket := range buckets {
   201  		_, err := tx.CreateTopLevelBucket(bucket)
   202  		if err != nil {
   203  			return err
   204  		}
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  // bdb returns the backing bolt.DB instance.
   211  //
   212  // NOTE: Part of the versionedDB interface.
   213  func (c *ClientDB) bdb() kvdb.Backend {
   214  	return c.db
   215  }
   216  
   217  // Version returns the database's current version number.
   218  //
   219  // NOTE: Part of the versionedDB interface.
   220  func (c *ClientDB) Version() (uint32, error) {
   221  	var version uint32
   222  	err := kvdb.View(c.db, func(tx kvdb.RTx) error {
   223  		var err error
   224  		version, err = getDBVersion(tx)
   225  		return err
   226  	}, func() {
   227  		version = 0
   228  	})
   229  	if err != nil {
   230  		return 0, err
   231  	}
   232  
   233  	return version, nil
   234  }
   235  
   236  // Close closes the underlying database.
   237  func (c *ClientDB) Close() error {
   238  	return c.db.Close()
   239  }
   240  
   241  // CreateTower initialize an address record used to communicate with a
   242  // watchtower. Each Tower is assigned a unique ID, that is used to amortize
   243  // storage costs of the public key when used by multiple sessions. If the tower
   244  // already exists, the address is appended to the list of all addresses used to
   245  // that tower previously and its corresponding sessions are marked as active.
   246  func (c *ClientDB) CreateTower(lnAddr *lnwire.NetAddress) (*Tower, error) {
   247  	var towerPubKey [33]byte
   248  	copy(towerPubKey[:], lnAddr.IdentityKey.SerializeCompressed())
   249  
   250  	var tower *Tower
   251  	err := kvdb.Update(c.db, func(tx kvdb.RwTx) error {
   252  		towerIndex := tx.ReadWriteBucket(cTowerIndexBkt)
   253  		if towerIndex == nil {
   254  			return ErrUninitializedDB
   255  		}
   256  
   257  		towers := tx.ReadWriteBucket(cTowerBkt)
   258  		if towers == nil {
   259  			return ErrUninitializedDB
   260  		}
   261  
   262  		// Check if the tower index already knows of this pubkey.
   263  		towerIDBytes := towerIndex.Get(towerPubKey[:])
   264  		if len(towerIDBytes) == 8 {
   265  			// The tower already exists, deserialize the existing
   266  			// record.
   267  			var err error
   268  			tower, err = getTower(towers, towerIDBytes)
   269  			if err != nil {
   270  				return err
   271  			}
   272  
   273  			// Add the new address to the existing tower. If the
   274  			// address is a duplicate, this will result in no
   275  			// change.
   276  			tower.AddAddress(lnAddr.Address)
   277  
   278  			// If there are any client sessions that correspond to
   279  			// this tower, we'll mark them as active to ensure we
   280  			// load them upon restarts.
   281  			//
   282  			// TODO(wilmer): with an index of tower -> sessions we
   283  			// can avoid the linear lookup.
   284  			sessions := tx.ReadWriteBucket(cSessionBkt)
   285  			if sessions == nil {
   286  				return ErrUninitializedDB
   287  			}
   288  			towerID := TowerIDFromBytes(towerIDBytes)
   289  			towerSessions, err := listClientSessions(
   290  				sessions, &towerID,
   291  			)
   292  			if err != nil {
   293  				return err
   294  			}
   295  			for _, session := range towerSessions {
   296  				err := markSessionStatus(
   297  					sessions, session, CSessionActive,
   298  				)
   299  				if err != nil {
   300  					return err
   301  				}
   302  			}
   303  		} else {
   304  			// No such tower exists, create a new tower id for our
   305  			// new tower. The error is unhandled since NextSequence
   306  			// never fails in an Update.
   307  			towerID, _ := towerIndex.NextSequence()
   308  
   309  			tower = &Tower{
   310  				ID:          TowerID(towerID),
   311  				IdentityKey: lnAddr.IdentityKey,
   312  				Addresses:   []net.Addr{lnAddr.Address},
   313  			}
   314  
   315  			towerIDBytes = tower.ID.Bytes()
   316  
   317  			// Since this tower is new, record the mapping from
   318  			// tower pubkey to tower id in the tower index.
   319  			err := towerIndex.Put(towerPubKey[:], towerIDBytes)
   320  			if err != nil {
   321  				return err
   322  			}
   323  		}
   324  
   325  		// Store the new or updated tower under its tower id.
   326  		return putTower(towers, tower)
   327  	}, func() {
   328  		tower = nil
   329  	})
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  
   334  	return tower, nil
   335  }
   336  
   337  // RemoveTower modifies a tower's record within the database. If an address is
   338  // provided, then _only_ the address record should be removed from the tower's
   339  // persisted state. Otherwise, we'll attempt to mark the tower as inactive by
   340  // marking all of its sessions inactive. If any of its sessions has unacked
   341  // updates, then ErrTowerUnackedUpdates is returned. If the tower doesn't have
   342  // any sessions at all, it'll be completely removed from the database.
   343  //
   344  // NOTE: An error is not returned if the tower doesn't exist.
   345  func (c *ClientDB) RemoveTower(pubKey *secp256k1.PublicKey, addr net.Addr) error {
   346  	return kvdb.Update(c.db, func(tx kvdb.RwTx) error {
   347  		towers := tx.ReadWriteBucket(cTowerBkt)
   348  		if towers == nil {
   349  			return ErrUninitializedDB
   350  		}
   351  		towerIndex := tx.ReadWriteBucket(cTowerIndexBkt)
   352  		if towerIndex == nil {
   353  			return ErrUninitializedDB
   354  		}
   355  
   356  		// Don't return an error if the watchtower doesn't exist to act
   357  		// as a NOP.
   358  		pubKeyBytes := pubKey.SerializeCompressed()
   359  		towerIDBytes := towerIndex.Get(pubKeyBytes)
   360  		if towerIDBytes == nil {
   361  			return nil
   362  		}
   363  
   364  		// If an address is provided, then we should _only_ remove the
   365  		// address record from the database.
   366  		if addr != nil {
   367  			tower, err := getTower(towers, towerIDBytes)
   368  			if err != nil {
   369  				return err
   370  			}
   371  
   372  			// Towers should always have at least one address saved.
   373  			tower.RemoveAddress(addr)
   374  			if len(tower.Addresses) == 0 {
   375  				return ErrLastTowerAddr
   376  			}
   377  
   378  			return putTower(towers, tower)
   379  		}
   380  
   381  		// Otherwise, we should attempt to mark the tower's sessions as
   382  		// inactive.
   383  		//
   384  		// TODO(wilmer): with an index of tower -> sessions we can avoid
   385  		// the linear lookup.
   386  		sessions := tx.ReadWriteBucket(cSessionBkt)
   387  		if sessions == nil {
   388  			return ErrUninitializedDB
   389  		}
   390  		towerID := TowerIDFromBytes(towerIDBytes)
   391  		towerSessions, err := listClientSessions(sessions, &towerID)
   392  		if err != nil {
   393  			return err
   394  		}
   395  
   396  		// If it doesn't have any, we can completely remove it from the
   397  		// database.
   398  		if len(towerSessions) == 0 {
   399  			if err := towerIndex.Delete(pubKeyBytes); err != nil {
   400  				return err
   401  			}
   402  			return towers.Delete(towerIDBytes)
   403  		}
   404  
   405  		// We'll mark its sessions as inactive as long as they don't
   406  		// have any pending updates to ensure we don't load them upon
   407  		// restarts.
   408  		for _, session := range towerSessions {
   409  			if len(session.CommittedUpdates) > 0 {
   410  				return ErrTowerUnackedUpdates
   411  			}
   412  			err := markSessionStatus(
   413  				sessions, session, CSessionInactive,
   414  			)
   415  			if err != nil {
   416  				return err
   417  			}
   418  		}
   419  
   420  		return nil
   421  	}, func() {})
   422  }
   423  
   424  // LoadTowerByID retrieves a tower by its tower ID.
   425  func (c *ClientDB) LoadTowerByID(towerID TowerID) (*Tower, error) {
   426  	var tower *Tower
   427  	err := kvdb.View(c.db, func(tx kvdb.RTx) error {
   428  		towers := tx.ReadBucket(cTowerBkt)
   429  		if towers == nil {
   430  			return ErrUninitializedDB
   431  		}
   432  
   433  		var err error
   434  		tower, err = getTower(towers, towerID.Bytes())
   435  		return err
   436  	}, func() {
   437  		tower = nil
   438  	})
   439  	if err != nil {
   440  		return nil, err
   441  	}
   442  
   443  	return tower, nil
   444  }
   445  
   446  // LoadTower retrieves a tower by its public key.
   447  func (c *ClientDB) LoadTower(pubKey *secp256k1.PublicKey) (*Tower, error) {
   448  	var tower *Tower
   449  	err := kvdb.View(c.db, func(tx kvdb.RTx) error {
   450  		towers := tx.ReadBucket(cTowerBkt)
   451  		if towers == nil {
   452  			return ErrUninitializedDB
   453  		}
   454  		towerIndex := tx.ReadBucket(cTowerIndexBkt)
   455  		if towerIndex == nil {
   456  			return ErrUninitializedDB
   457  		}
   458  
   459  		towerIDBytes := towerIndex.Get(pubKey.SerializeCompressed())
   460  		if towerIDBytes == nil {
   461  			return ErrTowerNotFound
   462  		}
   463  
   464  		var err error
   465  		tower, err = getTower(towers, towerIDBytes)
   466  		return err
   467  	}, func() {
   468  		tower = nil
   469  	})
   470  	if err != nil {
   471  		return nil, err
   472  	}
   473  
   474  	return tower, nil
   475  }
   476  
   477  // ListTowers retrieves the list of towers available within the database.
   478  func (c *ClientDB) ListTowers() ([]*Tower, error) {
   479  	var towers []*Tower
   480  	err := kvdb.View(c.db, func(tx kvdb.RTx) error {
   481  		towerBucket := tx.ReadBucket(cTowerBkt)
   482  		if towerBucket == nil {
   483  			return ErrUninitializedDB
   484  		}
   485  
   486  		return towerBucket.ForEach(func(towerIDBytes, _ []byte) error {
   487  			tower, err := getTower(towerBucket, towerIDBytes)
   488  			if err != nil {
   489  				return err
   490  			}
   491  			towers = append(towers, tower)
   492  			return nil
   493  		})
   494  	}, func() {
   495  		towers = nil
   496  	})
   497  	if err != nil {
   498  		return nil, err
   499  	}
   500  
   501  	return towers, nil
   502  }
   503  
   504  // NextSessionKeyIndex reserves a new session key derivation index for a
   505  // particular tower id. The index is reserved for that tower until
   506  // CreateClientSession is invoked for that tower and index, at which point a new
   507  // index for that tower can be reserved. Multiple calls to this method before
   508  // CreateClientSession is invoked should return the same index.
   509  func (c *ClientDB) NextSessionKeyIndex(towerID TowerID,
   510  	blobType blob.Type) (uint32, error) {
   511  
   512  	var index uint32
   513  	err := kvdb.Update(c.db, func(tx kvdb.RwTx) error {
   514  		keyIndex := tx.ReadWriteBucket(cSessionKeyIndexBkt)
   515  		if keyIndex == nil {
   516  			return ErrUninitializedDB
   517  		}
   518  
   519  		// Check the session key index to see if a key has already been
   520  		// reserved for this tower. If so, we'll deserialize and return
   521  		// the index directly.
   522  		var err error
   523  		index, err = getSessionKeyIndex(keyIndex, towerID, blobType)
   524  		if err == nil {
   525  			return nil
   526  		}
   527  
   528  		// Otherwise, generate a new session key index since the node
   529  		// doesn't already have reserved index. The error is ignored
   530  		// since NextSequence can't fail inside Update.
   531  		index64, _ := keyIndex.NextSequence()
   532  
   533  		// As a sanity check, assert that the index is still in the
   534  		// valid range of unhardened pubkeys. In the future, we should
   535  		// move to only using hardened keys, and this will prevent any
   536  		// overlap from occurring until then. This also prevents us from
   537  		// overflowing uint32s.
   538  		if index64 > math.MaxInt32 {
   539  			return fmt.Errorf("exhausted session key indexes")
   540  		}
   541  
   542  		// Create the key that will used to be store the reserved index.
   543  		keyBytes := createSessionKeyIndexKey(towerID, blobType)
   544  
   545  		index = uint32(index64)
   546  
   547  		var indexBuf [4]byte
   548  		byteOrder.PutUint32(indexBuf[:], index)
   549  
   550  		// Record the reserved session key index under this tower's id.
   551  		return keyIndex.Put(keyBytes, indexBuf[:])
   552  	}, func() {
   553  		index = 0
   554  	})
   555  	if err != nil {
   556  		return 0, err
   557  	}
   558  
   559  	return index, nil
   560  }
   561  
   562  // CreateClientSession records a newly negotiated client session in the set of
   563  // active sessions. The session can be identified by its SessionID.
   564  func (c *ClientDB) CreateClientSession(session *ClientSession) error {
   565  	return kvdb.Update(c.db, func(tx kvdb.RwTx) error {
   566  		keyIndexes := tx.ReadWriteBucket(cSessionKeyIndexBkt)
   567  		if keyIndexes == nil {
   568  			return ErrUninitializedDB
   569  		}
   570  
   571  		sessions := tx.ReadWriteBucket(cSessionBkt)
   572  		if sessions == nil {
   573  			return ErrUninitializedDB
   574  		}
   575  
   576  		// Check that  client session with this session id doesn't
   577  		// already exist.
   578  		existingSessionBytes := sessions.NestedReadWriteBucket(session.ID[:])
   579  		if existingSessionBytes != nil {
   580  			return ErrClientSessionAlreadyExists
   581  		}
   582  
   583  		towerID := session.TowerID
   584  		blobType := session.Policy.BlobType
   585  
   586  		// Check that this tower has a reserved key index.
   587  		index, err := getSessionKeyIndex(keyIndexes, towerID, blobType)
   588  		if err != nil {
   589  			return err
   590  		}
   591  
   592  		// Assert that the key index of the inserted session matches the
   593  		// reserved session key index.
   594  		if index != session.KeyIndex {
   595  			return ErrIncorrectKeyIndex
   596  		}
   597  
   598  		// Remove the key index reservation. For altruist commit
   599  		// sessions, we'll also purge under the old legacy key format.
   600  		key := createSessionKeyIndexKey(towerID, blobType)
   601  		err = keyIndexes.Delete(key)
   602  		if err != nil {
   603  			return err
   604  		}
   605  		if blobType == blob.TypeAltruistCommit {
   606  			err = keyIndexes.Delete(towerID.Bytes())
   607  			if err != nil {
   608  				return err
   609  			}
   610  		}
   611  
   612  		// Finally, write the client session's body in the sessions
   613  		// bucket.
   614  		return putClientSessionBody(sessions, session)
   615  	}, func() {})
   616  }
   617  
   618  // createSessionKeyIndexKey returns the indentifier used in the
   619  // session-key-index index, created as tower-id||blob-type.
   620  //
   621  // NOTE: The original serialization only used tower-id, which prevents
   622  // concurrent client types from reserving sessions with the same tower.
   623  func createSessionKeyIndexKey(towerID TowerID, blobType blob.Type) []byte {
   624  	towerIDBytes := towerID.Bytes()
   625  
   626  	// Session key indexes are stored under as tower-id||blob-type.
   627  	var keyBytes [6]byte
   628  	copy(keyBytes[:4], towerIDBytes)
   629  	byteOrder.PutUint16(keyBytes[4:], uint16(blobType))
   630  
   631  	return keyBytes[:]
   632  }
   633  
   634  // getSessionKeyIndex is a helper method
   635  func getSessionKeyIndex(keyIndexes kvdb.RwBucket, towerID TowerID,
   636  	blobType blob.Type) (uint32, error) {
   637  
   638  	// Session key indexes are store under as tower-id||blob-type. The
   639  	// original serialization only used tower-id, which prevents concurrent
   640  	// client types from reserving sessions with the same tower.
   641  	keyBytes := createSessionKeyIndexKey(towerID, blobType)
   642  
   643  	// Retrieve the index using the key bytes. If the key wasn't found, we
   644  	// will fall back to the legacy format that only uses the tower id, but
   645  	// _only_ if the blob type is for altruist commit sessions since that
   646  	// was the only operational session type prior to changing the key
   647  	// format.
   648  	keyIndexBytes := keyIndexes.Get(keyBytes)
   649  	if keyIndexBytes == nil && blobType == blob.TypeAltruistCommit {
   650  		keyIndexBytes = keyIndexes.Get(towerID.Bytes())
   651  	}
   652  
   653  	// All session key indexes should be serialized uint32's. If no key
   654  	// index was found, the length of keyIndexBytes will be 0.
   655  	if len(keyIndexBytes) != 4 {
   656  		return 0, ErrNoReservedKeyIndex
   657  	}
   658  
   659  	return byteOrder.Uint32(keyIndexBytes), nil
   660  }
   661  
   662  // ListClientSessions returns the set of all client sessions known to the db. An
   663  // optional tower ID can be used to filter out any client sessions in the
   664  // response that do not correspond to this tower.
   665  func (c *ClientDB) ListClientSessions(id *TowerID) (map[SessionID]*ClientSession, error) {
   666  	var clientSessions map[SessionID]*ClientSession
   667  	err := kvdb.View(c.db, func(tx kvdb.RTx) error {
   668  		sessions := tx.ReadBucket(cSessionBkt)
   669  		if sessions == nil {
   670  			return ErrUninitializedDB
   671  		}
   672  		var err error
   673  		clientSessions, err = listClientSessions(sessions, id)
   674  		return err
   675  	}, func() {
   676  		clientSessions = nil
   677  	})
   678  	if err != nil {
   679  		return nil, err
   680  	}
   681  
   682  	return clientSessions, nil
   683  }
   684  
   685  // listClientSessions returns the set of all client sessions known to the db. An
   686  // optional tower ID can be used to filter out any client sessions in the
   687  // response that do not correspond to this tower.
   688  func listClientSessions(sessions kvdb.RBucket,
   689  	id *TowerID) (map[SessionID]*ClientSession, error) {
   690  
   691  	clientSessions := make(map[SessionID]*ClientSession)
   692  	err := sessions.ForEach(func(k, _ []byte) error {
   693  		// We'll load the full client session since the client will need
   694  		// the CommittedUpdates and AckedUpdates on startup to resume
   695  		// committed updates and compute the highest known commit height
   696  		// for each channel.
   697  		session, err := getClientSession(sessions, k)
   698  		if err != nil {
   699  			return err
   700  		}
   701  
   702  		// Filter out any sessions that don't correspond to the given
   703  		// tower if one was set.
   704  		if id != nil && session.TowerID != *id {
   705  			return nil
   706  		}
   707  
   708  		clientSessions[session.ID] = session
   709  
   710  		return nil
   711  	})
   712  	if err != nil {
   713  		return nil, err
   714  	}
   715  
   716  	return clientSessions, nil
   717  }
   718  
   719  // FetchChanSummaries loads a mapping from all registered channels to their
   720  // channel summaries.
   721  func (c *ClientDB) FetchChanSummaries() (ChannelSummaries, error) {
   722  	var summaries map[lnwire.ChannelID]ClientChanSummary
   723  	err := kvdb.View(c.db, func(tx kvdb.RTx) error {
   724  		chanSummaries := tx.ReadBucket(cChanSummaryBkt)
   725  		if chanSummaries == nil {
   726  			return ErrUninitializedDB
   727  		}
   728  
   729  		return chanSummaries.ForEach(func(k, v []byte) error {
   730  			var chanID lnwire.ChannelID
   731  			copy(chanID[:], k)
   732  
   733  			var summary ClientChanSummary
   734  			err := summary.Decode(bytes.NewReader(v))
   735  			if err != nil {
   736  				return err
   737  			}
   738  
   739  			summaries[chanID] = summary
   740  
   741  			return nil
   742  		})
   743  	}, func() {
   744  		summaries = make(map[lnwire.ChannelID]ClientChanSummary)
   745  	})
   746  	if err != nil {
   747  		return nil, err
   748  	}
   749  
   750  	return summaries, nil
   751  }
   752  
   753  // RegisterChannel registers a channel for use within the client database. For
   754  // now, all that is stored in the channel summary is the sweep pkscript that
   755  // we'd like any tower sweeps to pay into. In the future, this will be extended
   756  // to contain more info to allow the client efficiently request historical
   757  // states to be backed up under the client's active policy.
   758  func (c *ClientDB) RegisterChannel(chanID lnwire.ChannelID,
   759  	sweepPkScript []byte) error {
   760  
   761  	return kvdb.Update(c.db, func(tx kvdb.RwTx) error {
   762  		chanSummaries := tx.ReadWriteBucket(cChanSummaryBkt)
   763  		if chanSummaries == nil {
   764  			return ErrUninitializedDB
   765  		}
   766  
   767  		_, err := getChanSummary(chanSummaries, chanID)
   768  		switch {
   769  
   770  		// Summary already exists.
   771  		case err == nil:
   772  			return ErrChannelAlreadyRegistered
   773  
   774  		// Channel is not registered, proceed with registration.
   775  		case err == ErrChannelNotRegistered:
   776  
   777  		// Unexpected error.
   778  		default:
   779  			return err
   780  		}
   781  
   782  		summary := ClientChanSummary{
   783  			SweepPkScript: sweepPkScript,
   784  		}
   785  
   786  		return putChanSummary(chanSummaries, chanID, &summary)
   787  	}, func() {})
   788  }
   789  
   790  // MarkBackupIneligible records that the state identified by the (channel id,
   791  // commit height) tuple was ineligible for being backed up under the current
   792  // policy. This state can be retried later under a different policy.
   793  func (c *ClientDB) MarkBackupIneligible(chanID lnwire.ChannelID,
   794  	commitHeight uint64) error {
   795  
   796  	return nil
   797  }
   798  
   799  // CommitUpdate persists the CommittedUpdate provided in the slot for (session,
   800  // seqNum). This allows the client to retransmit this update on startup.
   801  func (c *ClientDB) CommitUpdate(id *SessionID,
   802  	update *CommittedUpdate) (uint16, error) {
   803  
   804  	var lastApplied uint16
   805  	err := kvdb.Update(c.db, func(tx kvdb.RwTx) error {
   806  		sessions := tx.ReadWriteBucket(cSessionBkt)
   807  		if sessions == nil {
   808  			return ErrUninitializedDB
   809  		}
   810  
   811  		// We'll only load the ClientSession body for performance, since
   812  		// we primarily need to inspect its SeqNum and TowerLastApplied
   813  		// fields. The CommittedUpdates will be modified on disk
   814  		// directly.
   815  		session, err := getClientSessionBody(sessions, id[:])
   816  		if err != nil {
   817  			return err
   818  		}
   819  
   820  		// Can't fail if the above didn't fail.
   821  		sessionBkt := sessions.NestedReadWriteBucket(id[:])
   822  
   823  		// Ensure the session commits sub-bucket is initialized.
   824  		sessionCommits, err := sessionBkt.CreateBucketIfNotExists(
   825  			cSessionCommits,
   826  		)
   827  		if err != nil {
   828  			return err
   829  		}
   830  
   831  		var seqNumBuf [2]byte
   832  		byteOrder.PutUint16(seqNumBuf[:], update.SeqNum)
   833  
   834  		// Check to see if a committed update already exists for this
   835  		// sequence number.
   836  		committedUpdateBytes := sessionCommits.Get(seqNumBuf[:])
   837  		if committedUpdateBytes != nil {
   838  			var dbUpdate CommittedUpdate
   839  			err := dbUpdate.Decode(
   840  				bytes.NewReader(committedUpdateBytes),
   841  			)
   842  			if err != nil {
   843  				return err
   844  			}
   845  
   846  			// If an existing committed update has a different hint,
   847  			// we'll reject this newer update.
   848  			if dbUpdate.Hint != update.Hint {
   849  				return ErrUpdateAlreadyCommitted
   850  			}
   851  
   852  			// Otherwise, capture the last applied value and
   853  			// succeed.
   854  			lastApplied = session.TowerLastApplied
   855  			return nil
   856  		}
   857  
   858  		// There's no committed update for this sequence number, ensure
   859  		// that we are committing the next unallocated one.
   860  		if update.SeqNum != session.SeqNum+1 {
   861  			return ErrCommitUnorderedUpdate
   862  		}
   863  
   864  		// Increment the session's sequence number and store the updated
   865  		// client session.
   866  		//
   867  		// TODO(conner): split out seqnum and last applied own bucket to
   868  		// eliminate serialization of full struct during CommitUpdate?
   869  		// Can also read/write directly to byes [:2] without migration.
   870  		session.SeqNum++
   871  		err = putClientSessionBody(sessions, session)
   872  		if err != nil {
   873  			return err
   874  		}
   875  
   876  		// Encode and store the committed update in the sessionCommits
   877  		// sub-bucket under the requested sequence number.
   878  		var b bytes.Buffer
   879  		err = update.Encode(&b)
   880  		if err != nil {
   881  			return err
   882  		}
   883  
   884  		err = sessionCommits.Put(seqNumBuf[:], b.Bytes())
   885  		if err != nil {
   886  			return err
   887  		}
   888  
   889  		// Finally, capture the session's last applied value so it can
   890  		// be sent in the next state update to the tower.
   891  		lastApplied = session.TowerLastApplied
   892  
   893  		return nil
   894  
   895  	}, func() {
   896  		lastApplied = 0
   897  	})
   898  	if err != nil {
   899  		return 0, err
   900  	}
   901  
   902  	return lastApplied, nil
   903  }
   904  
   905  // AckUpdate persists an acknowledgment for a given (session, seqnum) pair. This
   906  // removes the update from the set of committed updates, and validates the
   907  // lastApplied value returned from the tower.
   908  func (c *ClientDB) AckUpdate(id *SessionID, seqNum uint16,
   909  	lastApplied uint16) error {
   910  
   911  	return kvdb.Update(c.db, func(tx kvdb.RwTx) error {
   912  		sessions := tx.ReadWriteBucket(cSessionBkt)
   913  		if sessions == nil {
   914  			return ErrUninitializedDB
   915  		}
   916  
   917  		// We'll only load the ClientSession body for performance, since
   918  		// we primarily need to inspect its SeqNum and TowerLastApplied
   919  		// fields. The CommittedUpdates and AckedUpdates will be
   920  		// modified on disk directly.
   921  		session, err := getClientSessionBody(sessions, id[:])
   922  		if err != nil {
   923  			return err
   924  		}
   925  
   926  		// If the tower has acked a sequence number beyond our highest
   927  		// sequence number, fail.
   928  		if lastApplied > session.SeqNum {
   929  			return ErrUnallocatedLastApplied
   930  		}
   931  
   932  		// If the tower acked with a lower sequence number than it gave
   933  		// us prior, fail.
   934  		if lastApplied < session.TowerLastApplied {
   935  			return ErrLastAppliedReversion
   936  		}
   937  
   938  		// TODO(conner): split out seqnum and last applied own bucket to
   939  		// eliminate serialization of full struct during AckUpdate?  Can
   940  		// also read/write directly to byes [2:4] without migration.
   941  		session.TowerLastApplied = lastApplied
   942  
   943  		// Write the client session with the updated last applied value.
   944  		err = putClientSessionBody(sessions, session)
   945  		if err != nil {
   946  			return err
   947  		}
   948  
   949  		// Can't fail because of getClientSession succeeded.
   950  		sessionBkt := sessions.NestedReadWriteBucket(id[:])
   951  
   952  		// If the commits sub-bucket doesn't exist, there can't possibly
   953  		// be a corresponding committed update to remove.
   954  		sessionCommits := sessionBkt.NestedReadWriteBucket(cSessionCommits)
   955  		if sessionCommits == nil {
   956  			return ErrCommittedUpdateNotFound
   957  		}
   958  
   959  		var seqNumBuf [2]byte
   960  		byteOrder.PutUint16(seqNumBuf[:], seqNum)
   961  
   962  		// Assert that a committed update exists for this sequence
   963  		// number.
   964  		committedUpdateBytes := sessionCommits.Get(seqNumBuf[:])
   965  		if committedUpdateBytes == nil {
   966  			return ErrCommittedUpdateNotFound
   967  		}
   968  
   969  		var committedUpdate CommittedUpdate
   970  		err = committedUpdate.Decode(
   971  			bytes.NewReader(committedUpdateBytes),
   972  		)
   973  		if err != nil {
   974  			return err
   975  		}
   976  
   977  		// Remove the corresponding committed update.
   978  		err = sessionCommits.Delete(seqNumBuf[:])
   979  		if err != nil {
   980  			return err
   981  		}
   982  
   983  		// Ensure that the session acks sub-bucket is initialized so we
   984  		// can insert an entry.
   985  		sessionAcks, err := sessionBkt.CreateBucketIfNotExists(
   986  			cSessionAcks,
   987  		)
   988  		if err != nil {
   989  			return err
   990  		}
   991  
   992  		// The session acks only need to track the backup id of the
   993  		// update, so we can discard the blob and hint.
   994  		var b bytes.Buffer
   995  		err = committedUpdate.BackupID.Encode(&b)
   996  		if err != nil {
   997  			return err
   998  		}
   999  
  1000  		// Finally, insert the ack into the sessionAcks sub-bucket.
  1001  		return sessionAcks.Put(seqNumBuf[:], b.Bytes())
  1002  	}, func() {})
  1003  }
  1004  
  1005  // getClientSessionBody loads the body of a ClientSession from the sessions
  1006  // bucket corresponding to the serialized session id. This does not deserialize
  1007  // the CommittedUpdates or AckUpdates associated with the session. If the caller
  1008  // requires this info, use getClientSession.
  1009  func getClientSessionBody(sessions kvdb.RBucket,
  1010  	idBytes []byte) (*ClientSession, error) {
  1011  
  1012  	sessionBkt := sessions.NestedReadBucket(idBytes)
  1013  	if sessionBkt == nil {
  1014  		return nil, ErrClientSessionNotFound
  1015  	}
  1016  
  1017  	// Should never have a sessionBkt without also having its body.
  1018  	sessionBody := sessionBkt.Get(cSessionBody)
  1019  	if sessionBody == nil {
  1020  		return nil, ErrCorruptClientSession
  1021  	}
  1022  
  1023  	var session ClientSession
  1024  	copy(session.ID[:], idBytes)
  1025  
  1026  	err := session.Decode(bytes.NewReader(sessionBody))
  1027  	if err != nil {
  1028  		return nil, err
  1029  	}
  1030  
  1031  	return &session, nil
  1032  }
  1033  
  1034  // getClientSession loads the full ClientSession associated with the serialized
  1035  // session id. This method populates the CommittedUpdates and AckUpdates in
  1036  // addition to the ClientSession's body.
  1037  func getClientSession(sessions kvdb.RBucket,
  1038  	idBytes []byte) (*ClientSession, error) {
  1039  
  1040  	session, err := getClientSessionBody(sessions, idBytes)
  1041  	if err != nil {
  1042  		return nil, err
  1043  	}
  1044  
  1045  	// Fetch the committed updates for this session.
  1046  	commitedUpdates, err := getClientSessionCommits(sessions, idBytes)
  1047  	if err != nil {
  1048  		return nil, err
  1049  	}
  1050  
  1051  	// Fetch the acked updates for this session.
  1052  	ackedUpdates, err := getClientSessionAcks(sessions, idBytes)
  1053  	if err != nil {
  1054  		return nil, err
  1055  	}
  1056  
  1057  	session.CommittedUpdates = commitedUpdates
  1058  	session.AckedUpdates = ackedUpdates
  1059  
  1060  	return session, nil
  1061  }
  1062  
  1063  // getClientSessionCommits retrieves all committed updates for the session
  1064  // identified by the serialized session id.
  1065  func getClientSessionCommits(sessions kvdb.RBucket,
  1066  	idBytes []byte) ([]CommittedUpdate, error) {
  1067  
  1068  	// Can't fail because client session body has already been read.
  1069  	sessionBkt := sessions.NestedReadBucket(idBytes)
  1070  
  1071  	// Initialize commitedUpdates so that we can return an initialized map
  1072  	// if no committed updates exist.
  1073  	committedUpdates := make([]CommittedUpdate, 0)
  1074  
  1075  	sessionCommits := sessionBkt.NestedReadBucket(cSessionCommits)
  1076  	if sessionCommits == nil {
  1077  		return committedUpdates, nil
  1078  	}
  1079  
  1080  	err := sessionCommits.ForEach(func(k, v []byte) error {
  1081  		var committedUpdate CommittedUpdate
  1082  		err := committedUpdate.Decode(bytes.NewReader(v))
  1083  		if err != nil {
  1084  			return err
  1085  		}
  1086  		committedUpdate.SeqNum = byteOrder.Uint16(k)
  1087  
  1088  		committedUpdates = append(committedUpdates, committedUpdate)
  1089  
  1090  		return nil
  1091  	})
  1092  	if err != nil {
  1093  		return nil, err
  1094  	}
  1095  
  1096  	return committedUpdates, nil
  1097  }
  1098  
  1099  // getClientSessionAcks retrieves all acked updates for the session identified
  1100  // by the serialized session id.
  1101  func getClientSessionAcks(sessions kvdb.RBucket,
  1102  	idBytes []byte) (map[uint16]BackupID, error) {
  1103  
  1104  	// Can't fail because client session body has already been read.
  1105  	sessionBkt := sessions.NestedReadBucket(idBytes)
  1106  
  1107  	// Initialize ackedUpdates so that we can return an initialized map if
  1108  	// no acked updates exist.
  1109  	ackedUpdates := make(map[uint16]BackupID)
  1110  
  1111  	sessionAcks := sessionBkt.NestedReadBucket(cSessionAcks)
  1112  	if sessionAcks == nil {
  1113  		return ackedUpdates, nil
  1114  	}
  1115  
  1116  	err := sessionAcks.ForEach(func(k, v []byte) error {
  1117  		seqNum := byteOrder.Uint16(k)
  1118  
  1119  		var backupID BackupID
  1120  		err := backupID.Decode(bytes.NewReader(v))
  1121  		if err != nil {
  1122  			return err
  1123  		}
  1124  
  1125  		ackedUpdates[seqNum] = backupID
  1126  
  1127  		return nil
  1128  	})
  1129  	if err != nil {
  1130  		return nil, err
  1131  	}
  1132  
  1133  	return ackedUpdates, nil
  1134  }
  1135  
  1136  // putClientSessionBody stores the body of the ClientSession (everything but the
  1137  // CommittedUpdates and AckedUpdates).
  1138  func putClientSessionBody(sessions kvdb.RwBucket,
  1139  	session *ClientSession) error {
  1140  
  1141  	sessionBkt, err := sessions.CreateBucketIfNotExists(session.ID[:])
  1142  	if err != nil {
  1143  		return err
  1144  	}
  1145  
  1146  	var b bytes.Buffer
  1147  	err = session.Encode(&b)
  1148  	if err != nil {
  1149  		return err
  1150  	}
  1151  
  1152  	return sessionBkt.Put(cSessionBody, b.Bytes())
  1153  }
  1154  
  1155  // markSessionStatus updates the persisted state of the session to the new
  1156  // status.
  1157  func markSessionStatus(sessions kvdb.RwBucket, session *ClientSession,
  1158  	status CSessionStatus) error {
  1159  
  1160  	session.Status = status
  1161  	return putClientSessionBody(sessions, session)
  1162  }
  1163  
  1164  // getChanSummary loads a ClientChanSummary for the passed chanID.
  1165  func getChanSummary(chanSummaries kvdb.RBucket,
  1166  	chanID lnwire.ChannelID) (*ClientChanSummary, error) {
  1167  
  1168  	chanSummaryBytes := chanSummaries.Get(chanID[:])
  1169  	if chanSummaryBytes == nil {
  1170  		return nil, ErrChannelNotRegistered
  1171  	}
  1172  
  1173  	var summary ClientChanSummary
  1174  	err := summary.Decode(bytes.NewReader(chanSummaryBytes))
  1175  	if err != nil {
  1176  		return nil, err
  1177  	}
  1178  
  1179  	return &summary, nil
  1180  }
  1181  
  1182  // putChanSummary stores a ClientChanSummary for the passed chanID.
  1183  func putChanSummary(chanSummaries kvdb.RwBucket, chanID lnwire.ChannelID,
  1184  	summary *ClientChanSummary) error {
  1185  
  1186  	var b bytes.Buffer
  1187  	err := summary.Encode(&b)
  1188  	if err != nil {
  1189  		return err
  1190  	}
  1191  
  1192  	return chanSummaries.Put(chanID[:], b.Bytes())
  1193  }
  1194  
  1195  // getTower loads a Tower identified by its serialized tower id.
  1196  func getTower(towers kvdb.RBucket, id []byte) (*Tower, error) {
  1197  	towerBytes := towers.Get(id)
  1198  	if towerBytes == nil {
  1199  		return nil, ErrTowerNotFound
  1200  	}
  1201  
  1202  	var tower Tower
  1203  	err := tower.Decode(bytes.NewReader(towerBytes))
  1204  	if err != nil {
  1205  		return nil, err
  1206  	}
  1207  
  1208  	tower.ID = TowerIDFromBytes(id)
  1209  
  1210  	return &tower, nil
  1211  }
  1212  
  1213  // putTower stores a Tower identified by its serialized tower id.
  1214  func putTower(towers kvdb.RwBucket, tower *Tower) error {
  1215  	var b bytes.Buffer
  1216  	err := tower.Encode(&b)
  1217  	if err != nil {
  1218  		return err
  1219  	}
  1220  
  1221  	return towers.Put(tower.ID.Bytes(), b.Bytes())
  1222  }