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  }