github.com/decred/dcrlnd@v0.7.6/channeldb/nodes.go (about) 1 package channeldb 2 3 import ( 4 "bytes" 5 "io" 6 "net" 7 "time" 8 9 "github.com/decred/dcrd/dcrec/secp256k1/v4" 10 "github.com/decred/dcrd/wire" 11 "github.com/decred/dcrlnd/kvdb" 12 ) 13 14 var ( 15 // nodeInfoBucket stores metadata pertaining to nodes that we've had 16 // direct channel-based correspondence with. This bucket allows one to 17 // query for all open channels pertaining to the node by exploring each 18 // node's sub-bucket within the openChanBucket. 19 nodeInfoBucket = []byte("nib") 20 ) 21 22 // LinkNode stores metadata related to node's that we have/had a direct 23 // channel open with. Information such as the Decred network the node 24 // advertised, and its identity public key are also stored. Additionally, this 25 // struct and the bucket its stored within have store data similar to that of 26 // Decred's addrmanager. The TCP address information stored within the struct 27 // can be used to establish persistent connections will all channel 28 // counterparties on daemon startup. 29 // 30 // TODO(roasbeef): also add current OnionKey plus rotation schedule? 31 // TODO(roasbeef): add bitfield for supported services 32 // - possibly add a wire.NetAddress type, type 33 type LinkNode struct { 34 // Network indicates the Decred network that the LinkNode advertises 35 // for incoming channel creation. 36 Network wire.CurrencyNet 37 38 // IdentityPub is the node's current identity public key. Any 39 // channel/topology related information received by this node MUST be 40 // signed by this public key. 41 IdentityPub *secp256k1.PublicKey 42 43 // LastSeen tracks the last time this node was seen within the network. 44 // A node should be marked as seen if the daemon either is able to 45 // establish an outgoing connection to the node or receives a new 46 // incoming connection from the node. This timestamp (stored in unix 47 // epoch) may be used within a heuristic which aims to determine when a 48 // channel should be unilaterally closed due to inactivity. 49 // 50 // TODO(roasbeef): replace with block hash/height? 51 // * possibly add a time-value metric into the heuristic? 52 LastSeen time.Time 53 54 // Addresses is a list of IP address in which either we were able to 55 // reach the node over in the past, OR we received an incoming 56 // authenticated connection for the stored identity public key. 57 Addresses []net.Addr 58 59 // db is the database instance this node was fetched from. This is used 60 // to sync back the node's state if it is updated. 61 db *LinkNodeDB 62 } 63 64 // NewLinkNode creates a new LinkNode from the provided parameters, which is 65 // backed by an instance of a link node DB. 66 func NewLinkNode(db *LinkNodeDB, bitNet wire.CurrencyNet, pub *secp256k1.PublicKey, 67 addrs ...net.Addr) *LinkNode { 68 69 filledAddrs := make([]net.Addr, 0, len(addrs)) 70 for _, addr := range addrs { 71 if addr == nil { 72 continue 73 } 74 filledAddrs = append(filledAddrs, addr) 75 } 76 77 return &LinkNode{ 78 Network: bitNet, 79 IdentityPub: pub, 80 LastSeen: time.Now(), 81 Addresses: filledAddrs, 82 db: db, 83 } 84 } 85 86 // UpdateLastSeen updates the last time this node was directly encountered on 87 // the Lightning Network. 88 func (l *LinkNode) UpdateLastSeen(lastSeen time.Time) error { 89 l.LastSeen = lastSeen 90 91 return l.Sync() 92 } 93 94 // AddAddress appends the specified TCP address to the list of known addresses 95 // this node is/was known to be reachable at. 96 func (l *LinkNode) AddAddress(addr net.Addr) error { 97 for _, a := range l.Addresses { 98 if a.String() == addr.String() { 99 return nil 100 } 101 } 102 103 l.Addresses = append(l.Addresses, addr) 104 105 return l.Sync() 106 } 107 108 // Sync performs a full database sync which writes the current up-to-date data 109 // within the struct to the database. 110 func (l *LinkNode) Sync() error { 111 // Finally update the database by storing the link node and updating 112 // any relevant indexes. 113 return kvdb.Update(l.db.backend, func(tx kvdb.RwTx) error { 114 nodeMetaBucket := tx.ReadWriteBucket(nodeInfoBucket) 115 if nodeMetaBucket == nil { 116 return ErrLinkNodesNotFound 117 } 118 119 return putLinkNode(nodeMetaBucket, l) 120 }, func() {}) 121 } 122 123 // putLinkNode serializes then writes the encoded version of the passed link 124 // node into the nodeMetaBucket. This function is provided in order to allow 125 // the ability to re-use a database transaction across many operations. 126 func putLinkNode(nodeMetaBucket kvdb.RwBucket, l *LinkNode) error { 127 // First serialize the LinkNode into its raw-bytes encoding. 128 var b bytes.Buffer 129 if err := serializeLinkNode(&b, l); err != nil { 130 return err 131 } 132 133 // Finally insert the link-node into the node metadata bucket keyed 134 // according to the its pubkey serialized in compressed form. 135 nodePub := l.IdentityPub.SerializeCompressed() 136 return nodeMetaBucket.Put(nodePub, b.Bytes()) 137 } 138 139 // LinkNodeDB is a database that keeps track of all link nodes. 140 type LinkNodeDB struct { 141 backend kvdb.Backend 142 } 143 144 // DeleteLinkNode removes the link node with the given identity from the 145 // database. 146 func (l *LinkNodeDB) DeleteLinkNode(identity *secp256k1.PublicKey) error { 147 return kvdb.Update(l.backend, func(tx kvdb.RwTx) error { 148 return deleteLinkNode(tx, identity) 149 }, func() {}) 150 } 151 152 func deleteLinkNode(tx kvdb.RwTx, identity *secp256k1.PublicKey) error { 153 nodeMetaBucket := tx.ReadWriteBucket(nodeInfoBucket) 154 if nodeMetaBucket == nil { 155 return ErrLinkNodesNotFound 156 } 157 158 pubKey := identity.SerializeCompressed() 159 return nodeMetaBucket.Delete(pubKey) 160 } 161 162 // FetchLinkNode attempts to lookup the data for a LinkNode based on a target 163 // identity public key. If a particular LinkNode for the passed identity public 164 // key cannot be found, then ErrNodeNotFound if returned. 165 func (l *LinkNodeDB) FetchLinkNode(identity *secp256k1.PublicKey) (*LinkNode, error) { 166 var linkNode *LinkNode 167 err := kvdb.View(l.backend, func(tx kvdb.RTx) error { 168 node, err := fetchLinkNode(tx, identity) 169 if err != nil { 170 return err 171 } 172 173 linkNode = node 174 return nil 175 }, func() { 176 linkNode = nil 177 }) 178 179 return linkNode, err 180 } 181 182 func fetchLinkNode(tx kvdb.RTx, targetPub *secp256k1.PublicKey) (*LinkNode, error) { 183 // First fetch the bucket for storing node metadata, bailing out early 184 // if it hasn't been created yet. 185 nodeMetaBucket := tx.ReadBucket(nodeInfoBucket) 186 if nodeMetaBucket == nil { 187 return nil, ErrLinkNodesNotFound 188 } 189 190 // If a link node for that particular public key cannot be located, 191 // then exit early with an ErrNodeNotFound. 192 pubKey := targetPub.SerializeCompressed() 193 nodeBytes := nodeMetaBucket.Get(pubKey) 194 if nodeBytes == nil { 195 return nil, ErrNodeNotFound 196 } 197 198 // Finally, decode and allocate a fresh LinkNode object to be returned 199 // to the caller. 200 nodeReader := bytes.NewReader(nodeBytes) 201 return deserializeLinkNode(nodeReader) 202 } 203 204 // TODO(roasbeef): update link node addrs in server upon connection 205 206 // FetchAllLinkNodes starts a new database transaction to fetch all nodes with 207 // whom we have active channels with. 208 func (l *LinkNodeDB) FetchAllLinkNodes() ([]*LinkNode, error) { 209 var linkNodes []*LinkNode 210 err := kvdb.View(l.backend, func(tx kvdb.RTx) error { 211 nodes, err := fetchAllLinkNodes(tx) 212 if err != nil { 213 return err 214 } 215 216 linkNodes = nodes 217 return nil 218 }, func() { 219 linkNodes = nil 220 }) 221 if err != nil { 222 return nil, err 223 } 224 225 return linkNodes, nil 226 } 227 228 // fetchAllLinkNodes uses an existing database transaction to fetch all nodes 229 // with whom we have active channels with. 230 func fetchAllLinkNodes(tx kvdb.RTx) ([]*LinkNode, error) { 231 nodeMetaBucket := tx.ReadBucket(nodeInfoBucket) 232 if nodeMetaBucket == nil { 233 return nil, ErrLinkNodesNotFound 234 } 235 236 var linkNodes []*LinkNode 237 err := nodeMetaBucket.ForEach(func(k, v []byte) error { 238 if v == nil { 239 return nil 240 } 241 242 nodeReader := bytes.NewReader(v) 243 linkNode, err := deserializeLinkNode(nodeReader) 244 if err != nil { 245 return err 246 } 247 248 linkNodes = append(linkNodes, linkNode) 249 return nil 250 }) 251 if err != nil { 252 return nil, err 253 } 254 255 return linkNodes, nil 256 } 257 258 func serializeLinkNode(w io.Writer, l *LinkNode) error { 259 var buf [8]byte 260 261 byteOrder.PutUint32(buf[:4], uint32(l.Network)) 262 if _, err := w.Write(buf[:4]); err != nil { 263 return err 264 } 265 266 serializedID := l.IdentityPub.SerializeCompressed() 267 if _, err := w.Write(serializedID); err != nil { 268 return err 269 } 270 271 seenUnix := uint64(l.LastSeen.Unix()) 272 byteOrder.PutUint64(buf[:], seenUnix) 273 if _, err := w.Write(buf[:]); err != nil { 274 return err 275 } 276 277 numAddrs := uint32(len(l.Addresses)) 278 byteOrder.PutUint32(buf[:4], numAddrs) 279 if _, err := w.Write(buf[:4]); err != nil { 280 return err 281 } 282 283 for _, addr := range l.Addresses { 284 if err := serializeAddr(w, addr); err != nil { 285 return err 286 } 287 } 288 289 return nil 290 } 291 292 func deserializeLinkNode(r io.Reader) (*LinkNode, error) { 293 var ( 294 err error 295 buf [8]byte 296 ) 297 298 node := &LinkNode{} 299 300 if _, err := io.ReadFull(r, buf[:4]); err != nil { 301 return nil, err 302 } 303 node.Network = wire.CurrencyNet(byteOrder.Uint32(buf[:4])) 304 305 var pub [33]byte 306 if _, err := io.ReadFull(r, pub[:]); err != nil { 307 return nil, err 308 } 309 node.IdentityPub, err = secp256k1.ParsePubKey(pub[:]) 310 if err != nil { 311 return nil, err 312 } 313 314 if _, err := io.ReadFull(r, buf[:]); err != nil { 315 return nil, err 316 } 317 node.LastSeen = time.Unix(int64(byteOrder.Uint64(buf[:])), 0) 318 319 if _, err := io.ReadFull(r, buf[:4]); err != nil { 320 return nil, err 321 } 322 numAddrs := byteOrder.Uint32(buf[:4]) 323 324 node.Addresses = make([]net.Addr, numAddrs) 325 for i := uint32(0); i < numAddrs; i++ { 326 addr, err := deserializeAddr(r) 327 if err != nil { 328 return nil, err 329 } 330 node.Addresses[i] = addr 331 } 332 333 return node, nil 334 }