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

     1  package wtdb
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  
     9  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    10  	"github.com/decred/dcrlnd/lnwire"
    11  )
    12  
    13  // TowerID is a unique 64-bit identifier allocated to each unique watchtower.
    14  // This allows the client to conserve on-disk space by not needing to always
    15  // reference towers by their pubkey.
    16  type TowerID uint64
    17  
    18  // TowerIDFromBytes constructs a TowerID from the provided byte slice. The
    19  // argument must have at least 8 bytes, and should contain the TowerID in
    20  // big-endian byte order.
    21  func TowerIDFromBytes(towerIDBytes []byte) TowerID {
    22  	return TowerID(byteOrder.Uint64(towerIDBytes))
    23  }
    24  
    25  // Bytes encodes a TowerID into an 8-byte slice in big-endian byte order.
    26  func (id TowerID) Bytes() []byte {
    27  	var buf [8]byte
    28  	byteOrder.PutUint64(buf[:], uint64(id))
    29  	return buf[:]
    30  }
    31  
    32  // Tower holds the necessary components required to connect to a remote tower.
    33  // Communication is handled by brontide, and requires both a public key and an
    34  // address.
    35  type Tower struct {
    36  	// ID is a unique ID for this record assigned by the database.
    37  	ID TowerID
    38  
    39  	// IdentityKey is the public key of the remote node, used to
    40  	// authenticate the brontide transport.
    41  	IdentityKey *secp256k1.PublicKey
    42  
    43  	// Addresses is a list of possible addresses to reach the tower.
    44  	Addresses []net.Addr
    45  }
    46  
    47  // AddAddress adds the given address to the tower's in-memory list of addresses.
    48  // If the address's string is already present, the Tower will be left
    49  // unmodified. Otherwise, the adddress is prepended to the beginning of the
    50  // Tower's addresses, on the assumption that it is fresher than the others.
    51  //
    52  // NOTE: This method is NOT safe for concurrent use.
    53  func (t *Tower) AddAddress(addr net.Addr) {
    54  	// Ensure we don't add a duplicate address.
    55  	addrStr := addr.String()
    56  	for _, existingAddr := range t.Addresses {
    57  		if existingAddr.String() == addrStr {
    58  			return
    59  		}
    60  	}
    61  
    62  	// Add this address to the front of the list, on the assumption that it
    63  	// is a fresher address and will be tried first.
    64  	t.Addresses = append([]net.Addr{addr}, t.Addresses...)
    65  }
    66  
    67  // RemoveAddress removes the given address from the tower's in-memory list of
    68  // addresses. If the address doesn't exist, then this will act as a NOP.
    69  func (t *Tower) RemoveAddress(addr net.Addr) {
    70  	addrStr := addr.String()
    71  	for i, address := range t.Addresses {
    72  		if address.String() != addrStr {
    73  			continue
    74  		}
    75  		t.Addresses = append(t.Addresses[:i], t.Addresses[i+1:]...)
    76  		return
    77  	}
    78  }
    79  
    80  // LNAddrs generates a list of lnwire.NetAddress from a Tower instance's
    81  // addresses. This can be used to have a client try multiple addresses for the
    82  // same Tower.
    83  //
    84  // NOTE: This method is NOT safe for concurrent use.
    85  func (t *Tower) LNAddrs() []*lnwire.NetAddress {
    86  	addrs := make([]*lnwire.NetAddress, 0, len(t.Addresses))
    87  	for _, addr := range t.Addresses {
    88  		addrs = append(addrs, &lnwire.NetAddress{
    89  			IdentityKey: t.IdentityKey,
    90  			Address:     addr,
    91  		})
    92  	}
    93  
    94  	return addrs
    95  }
    96  
    97  // String returns a user-friendly identifier of the tower.
    98  func (t *Tower) String() string {
    99  	pubKey := hex.EncodeToString(t.IdentityKey.SerializeCompressed())
   100  	if len(t.Addresses) == 0 {
   101  		return pubKey
   102  	}
   103  	return fmt.Sprintf("%v@%v", pubKey, t.Addresses[0])
   104  }
   105  
   106  // Encode writes the Tower to the passed io.Writer. The TowerID is not
   107  // serialized, since it acts as the key.
   108  func (t *Tower) Encode(w io.Writer) error {
   109  	return WriteElements(w,
   110  		t.IdentityKey,
   111  		t.Addresses,
   112  	)
   113  }
   114  
   115  // Decode reads a Tower from the passed io.Reader. The TowerID is meant to be
   116  // decoded from the key.
   117  func (t *Tower) Decode(r io.Reader) error {
   118  	return ReadElements(r,
   119  		&t.IdentityKey,
   120  		&t.Addresses,
   121  	)
   122  }