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  }