channeldb: add FullSyncWithAddr method to OpenChannel

This commit adds a new method ‘FullSyncWithAddr’ which is identical to
the existing ‘FullSync’ method other than it also creates an
association from the channel to a LinkNode object within the database.

This new method is required in order to create persistent links between
channels and link nodes which will later allow the development of
heuristics which decided when it “makes sense” to close a channel due
to inactivity. Additionally, this new association will allow for a
sub-system within the daemon to attempt to establish persistent
connections out to all LinkNodes in order to strive for channel
availability.
This commit is contained in:
Olaoluwa Osuntokun 2016-10-26 14:47:02 -07:00
parent f5d1785ab2
commit 3354685292
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"net"
"sync" "sync"
"time" "time"
@ -166,47 +167,90 @@ type OpenChannel struct {
// FullSync serializes, and writes to disk the *full* channel state, using // FullSync serializes, and writes to disk the *full* channel state, using
// both the active channel bucket to store the prefixed column fields, and the // both the active channel bucket to store the prefixed column fields, and the
// remote node's ID to store the remainder of the channel state. // remote node's ID to store the remainder of the channel state.
//
// NOTE: This method requires an active EncryptorDecryptor to be registered in
// order to encrypt sensitive information.
func (c *OpenChannel) FullSync() error { func (c *OpenChannel) FullSync() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
return c.Db.store.Update(c.fullSync)
}
// fullSync is an internal versino of the FullSync method which allows callers
// to sync the contents of an OpenChannel while re-using an existing database
// transaction.
func (c *OpenChannel) fullSync(tx *bolt.Tx) error {
// TODO(roasbeef): add helper funcs to create scoped update
// First fetch the top level bucket which stores all data related to
// current, active channels.
chanBucket, err := tx.CreateBucketIfNotExists(openChannelBucket)
if err != nil {
return err
}
// Within this top level bucket, fetch the bucket dedicated to storing
// open channel data specific to the remote node.
nodePub := c.IdentityPub.SerializeCompressed()
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(nodePub)
if err != nil {
return err
}
// Add this channel ID to the node's active channel index if
// it doesn't already exist.
chanIDBucket, err := nodeChanBucket.CreateBucketIfNotExists(chanIDBucket)
if err != nil {
return err
}
var b bytes.Buffer
if err := writeOutpoint(&b, c.ChanID); err != nil {
return err
}
if chanIDBucket.Get(b.Bytes()) == nil {
if err := chanIDBucket.Put(b.Bytes(), nil); err != nil {
return err
}
}
return putOpenChannel(chanBucket, nodeChanBucket, c)
}
// FullSyncWithAddr is identical to the FullSync function in that it writes the
// full channel state to disk. Additionally, this function also creates a
// LinkNode relationship between this newly created channel and an existing of
// new LinkNode instance. Syncing with this method rather than FullSync is
// required in order to allow listing all channels in the database globally, or
// according to the LinkNode they were created with.
//
// TODO(roasbeef): addr param should eventually be a lnwire.NetAddress type
// that includes service bits.
func (c *OpenChannel) FullSyncWithAddr(addr *net.TCPAddr) error {
c.Lock()
defer c.Unlock()
return c.Db.store.Update(func(tx *bolt.Tx) error { return c.Db.store.Update(func(tx *bolt.Tx) error {
// TODO(roasbeef): add helper funcs to create scoped update // First, sync all the persistent channel state to disk.
// First fetch the top level bucket which stores all data related to if err := c.fullSync(tx); err != nil {
// current, active channels. return err
chanBucket, err := tx.CreateBucketIfNotExists(openChannelBucket) }
nodeInfoBucket, err := tx.CreateBucketIfNotExists(nodeInfoBucket)
if err != nil { if err != nil {
return err return err
} }
// Within this top level bucket, fetch the bucket dedicated to storing // If a LinkNode for this identity public key already exsits, then
// open channel data specific to the remote node. // we can exit early.
nodePub := c.IdentityPub.SerializeCompressed() nodePub := c.IdentityPub.SerializeCompressed()
nodeChanBucket, err := chanBucket.CreateBucketIfNotExists(nodePub) if nodeInfoBucket.Get(nodePub) != nil {
if err != nil { return nil
return err
} }
// Add this channel ID to the node's active channel index if // Next, we need to establish a (possibly) new LinkNode
// it doesn't already exist. // relationship for this channel. The LinkNode meta-data contains
chanIDBucket, err := nodeChanBucket.CreateBucketIfNotExists(chanIDBucket) // reachability, up-time, and service bits related information.
if err != nil { // TODO(roasbeef): net info shuld be in lnwire.NetAddress
return err linkNode := c.Db.NewLinkNode(wire.MainNet, c.IdentityPub, addr)
}
var b bytes.Buffer
if err := writeOutpoint(&b, c.ChanID); err != nil {
return err
}
if chanIDBucket.Get(b.Bytes()) == nil {
if err := chanIDBucket.Put(b.Bytes(), nil); err != nil {
return err
}
}
return putOpenChannel(chanBucket, nodeChanBucket, c) return putLinkNode(nodeInfoBucket, linkNode)
}) })
} }