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 }