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 }