github.com/decred/dcrlnd@v0.7.6/watchtower/wtdb/client_session.go (about) 1 package wtdb 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/decred/dcrlnd/keychain" 8 "github.com/decred/dcrlnd/lnwire" 9 "github.com/decred/dcrlnd/watchtower/blob" 10 "github.com/decred/dcrlnd/watchtower/wtpolicy" 11 ) 12 13 // CSessionStatus is a bit-field representing the possible statuses of 14 // ClientSessions. 15 type CSessionStatus uint8 16 17 const ( 18 // CSessionActive indicates that the ClientSession is active and can be 19 // used for backups. 20 CSessionActive CSessionStatus = 0 21 22 // CSessionInactive indicates that the ClientSession is inactive and 23 // cannot be used for backups. 24 CSessionInactive CSessionStatus = 1 25 ) 26 27 // ClientSession encapsulates a SessionInfo returned from a successful 28 // session negotiation, and also records the tower and ephemeral secret used for 29 // communicating with the tower. 30 type ClientSession struct { 31 // ID is the client's public key used when authenticating with the 32 // tower. 33 // 34 // NOTE: This value is not serialized with the body of the struct, it 35 // should be set and recovered as the ClientSession's key. 36 ID SessionID 37 38 ClientSessionBody 39 40 // CommittedUpdates is a sorted list of unacked updates. These updates 41 // can be resent after a restart if the updates failed to send or 42 // receive an acknowledgment. 43 // 44 // NOTE: This list is serialized in it's own bucket, separate from the 45 // body of the ClientSession. The representation on disk is a key value 46 // map from sequence number to CommittedUpdateBody to allow efficient 47 // insertion and retrieval. 48 CommittedUpdates []CommittedUpdate 49 50 // AckedUpdates is a map from sequence number to backup id to record 51 // which revoked states were uploaded via this session. 52 // 53 // NOTE: This map is serialized in it's own bucket, separate from the 54 // body of the ClientSession. 55 AckedUpdates map[uint16]BackupID 56 57 // Tower holds the pubkey and address of the watchtower. 58 // 59 // NOTE: This value is not serialized. It is recovered by looking up the 60 // tower with TowerID. 61 Tower *Tower 62 63 // SessionKeyECDH is the ECDH capable wrapper of the ephemeral secret 64 // key used to connect to the watchtower. 65 // 66 // NOTE: This value is not serialized. It is derived using the KeyIndex 67 // on startup to avoid storing private keys on disk. 68 SessionKeyECDH keychain.SingleKeyECDH 69 } 70 71 // ClientSessionBody represents the primary components of a ClientSession that 72 // are serialized together within the database. The CommittedUpdates and 73 // AckedUpdates are serialized in buckets separate from the body. 74 type ClientSessionBody struct { 75 // SeqNum is the next unallocated sequence number that can be sent to 76 // the tower. 77 SeqNum uint16 78 79 // TowerLastApplied the last last-applied the tower has echoed back. 80 TowerLastApplied uint16 81 82 // TowerID is the unique, db-assigned identifier that references the 83 // Tower with which the session is negotiated. 84 TowerID TowerID 85 86 // KeyIndex is the index of key locator used to derive the client's 87 // session key so that it can authenticate with the tower to update its 88 // session. In order to rederive the private key, the key locator should 89 // use the keychain.KeyFamilyTowerSession key family. 90 KeyIndex uint32 91 92 // Policy holds the negotiated session parameters. 93 Policy wtpolicy.Policy 94 95 // Status indicates the current state of the ClientSession. 96 Status CSessionStatus 97 98 // RewardPkScript is the pkscript that the tower's reward will be 99 // deposited to if a sweep transaction confirms and the sessions 100 // specifies a reward output. 101 RewardPkScript []byte 102 } 103 104 // Encode writes a ClientSessionBody to the passed io.Writer. 105 func (s *ClientSessionBody) Encode(w io.Writer) error { 106 return WriteElements(w, 107 s.SeqNum, 108 s.TowerLastApplied, 109 uint64(s.TowerID), 110 s.KeyIndex, 111 uint8(s.Status), 112 s.Policy, 113 s.RewardPkScript, 114 ) 115 } 116 117 // Decode reads a ClientSessionBody from the passed io.Reader. 118 func (s *ClientSessionBody) Decode(r io.Reader) error { 119 var ( 120 towerID uint64 121 status uint8 122 ) 123 err := ReadElements(r, 124 &s.SeqNum, 125 &s.TowerLastApplied, 126 &towerID, 127 &s.KeyIndex, 128 &status, 129 &s.Policy, 130 &s.RewardPkScript, 131 ) 132 if err != nil { 133 return err 134 } 135 136 s.TowerID = TowerID(towerID) 137 s.Status = CSessionStatus(status) 138 139 return nil 140 } 141 142 // BackupID identifies a particular revoked, remote commitment by channel id and 143 // commitment height. 144 type BackupID struct { 145 // ChanID is the channel id of the revoked commitment. 146 ChanID lnwire.ChannelID 147 148 // CommitHeight is the commitment height of the revoked commitment. 149 CommitHeight uint64 150 } 151 152 // Encode writes the BackupID from the passed io.Writer. 153 func (b *BackupID) Encode(w io.Writer) error { 154 return WriteElements(w, 155 b.ChanID, 156 b.CommitHeight, 157 ) 158 } 159 160 // Decode reads a BackupID from the passed io.Reader. 161 func (b *BackupID) Decode(r io.Reader) error { 162 return ReadElements(r, 163 &b.ChanID, 164 &b.CommitHeight, 165 ) 166 } 167 168 // String returns a human-readable encoding of a BackupID. 169 func (b BackupID) String() string { 170 return fmt.Sprintf("backup(%v, %d)", b.ChanID, b.CommitHeight) 171 } 172 173 // CommittedUpdate holds a state update sent by a client along with its 174 // allocated sequence number and the exact remote commitment the encrypted 175 // justice transaction can rectify. 176 type CommittedUpdate struct { 177 // SeqNum is the unique sequence number allocated by the session to this 178 // update. 179 SeqNum uint16 180 181 CommittedUpdateBody 182 } 183 184 // CommittedUpdateBody represents the primary components of a CommittedUpdate. 185 // On disk, this is stored under the sequence number, which acts as its key. 186 type CommittedUpdateBody struct { 187 // BackupID identifies the breached commitment that the encrypted blob 188 // can spend from. 189 BackupID BackupID 190 191 // Hint is the 16-byte prefix of the revoked commitment transaction ID. 192 Hint blob.BreachHint 193 194 // EncryptedBlob is a ciphertext containing the sweep information for 195 // exacting justice if the commitment transaction matching the breach 196 // hint is broadcast. 197 EncryptedBlob []byte 198 } 199 200 // Encode writes the CommittedUpdateBody to the passed io.Writer. 201 func (u *CommittedUpdateBody) Encode(w io.Writer) error { 202 err := u.BackupID.Encode(w) 203 if err != nil { 204 return err 205 } 206 207 return WriteElements(w, 208 u.Hint, 209 u.EncryptedBlob, 210 ) 211 } 212 213 // Decode reads a CommittedUpdateBody from the passed io.Reader. 214 func (u *CommittedUpdateBody) Decode(r io.Reader) error { 215 err := u.BackupID.Decode(r) 216 if err != nil { 217 return err 218 } 219 220 return ReadElements(r, 221 &u.Hint, 222 &u.EncryptedBlob, 223 ) 224 }