mirror of https://github.com/BTCPrivate/lnd.git
channeldb+funding: track opening height using MarkChannelAsOpen
This commit modifies the OpenChannel structure on-disk to also track that opening height of a channel. This change is being made in order to make and more light client friendly. A follow up commit will modify several areas of the codebase to use this new functionality.
This commit is contained in:
parent
373a1192ce
commit
a5113c2439
|
@ -70,6 +70,7 @@ var (
|
||||||
satReceivedPrefix = []byte("srp")
|
satReceivedPrefix = []byte("srp")
|
||||||
netFeesPrefix = []byte("ntp")
|
netFeesPrefix = []byte("ntp")
|
||||||
isPendingPrefix = []byte("pdg")
|
isPendingPrefix = []byte("pdg")
|
||||||
|
openHeightPrefix = []byte("open-height-prefix")
|
||||||
|
|
||||||
// chanIDKey stores the node, and channelID for an active channel.
|
// chanIDKey stores the node, and channelID for an active channel.
|
||||||
chanIDKey = []byte("cik")
|
chanIDKey = []byte("cik")
|
||||||
|
@ -129,6 +130,10 @@ const (
|
||||||
// to an on-disk log, which can then subsequently be queried in order to
|
// to an on-disk log, which can then subsequently be queried in order to
|
||||||
// "time-travel" to a prior state.
|
// "time-travel" to a prior state.
|
||||||
type OpenChannel struct {
|
type OpenChannel struct {
|
||||||
|
// OpeningHeight is the height in which this channel was officially
|
||||||
|
// marked open.
|
||||||
|
OpeningHeight uint32
|
||||||
|
|
||||||
// IdentityPub is the identity public key of the remote node this
|
// IdentityPub is the identity public key of the remote node this
|
||||||
// channel has been established with.
|
// channel has been established with.
|
||||||
IdentityPub *btcec.PublicKey
|
IdentityPub *btcec.PublicKey
|
||||||
|
@ -356,17 +361,18 @@ func (c *OpenChannel) SyncPending(addr *net.TCPAddr) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a LinkNode for this identity public key already exsits, then
|
// If a LinkNode for this identity public key already exists,
|
||||||
// we can exit early.
|
// then we can exit early.
|
||||||
nodePub := c.IdentityPub.SerializeCompressed()
|
nodePub := c.IdentityPub.SerializeCompressed()
|
||||||
if nodeInfoBucket.Get(nodePub) != nil {
|
if nodeInfoBucket.Get(nodePub) != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, we need to establish a (possibly) new LinkNode
|
// Next, we need to establish a (possibly) new LinkNode
|
||||||
// relationship for this channel. The LinkNode metadata contains
|
// relationship for this channel. The LinkNode metadata
|
||||||
// reachability, up-time, and service bits related information.
|
// contains reachability, up-time, and service bits related
|
||||||
// TODO(roasbeef): net info shuld be in lnwire.NetAddress
|
// information.
|
||||||
|
// TODO(roasbeef): net info should be in lnwire.NetAddress
|
||||||
linkNode := c.Db.NewLinkNode(wire.MainNet, c.IdentityPub, addr)
|
linkNode := c.Db.NewLinkNode(wire.MainNet, c.IdentityPub, addr)
|
||||||
|
|
||||||
return putLinkNode(nodeInfoBucket, linkNode)
|
return putLinkNode(nodeInfoBucket, linkNode)
|
||||||
|
@ -966,6 +972,9 @@ func putOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
|
||||||
if err := putChanIsPending(openChanBucket, channel); err != nil {
|
if err := putChanIsPending(openChanBucket, channel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := putChanOpenHeight(openChanBucket, channel); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Next, write out the fields of the channel update less frequently.
|
// Next, write out the fields of the channel update less frequently.
|
||||||
if err := putChannelIDs(nodeChanBucket, channel); err != nil {
|
if err := putChannelIDs(nodeChanBucket, channel); err != nil {
|
||||||
|
@ -1053,6 +1062,9 @@ func fetchOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
|
||||||
if err = fetchChanIsPending(openChanBucket, channel); err != nil {
|
if err = fetchChanIsPending(openChanBucket, channel); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := fetchChanOpenHeight(openChanBucket, channel); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return channel, nil
|
return channel, nil
|
||||||
}
|
}
|
||||||
|
@ -1083,6 +1095,9 @@ func deleteOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket,
|
||||||
if err := deleteChanIsPending(openChanBucket, channelID); err != nil {
|
if err := deleteChanIsPending(openChanBucket, channelID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := deleteChanOpenHeight(openChanBucket, channelID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Finally, delete all the fields directly within the node's channel
|
// Finally, delete all the fields directly within the node's channel
|
||||||
// bucket.
|
// bucket.
|
||||||
|
@ -1447,6 +1462,44 @@ func fetchChanIsPending(openChanBucket *bolt.Bucket, channel *OpenChannel) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func putChanOpenHeight(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := writeOutpoint(&b, channel.ChanID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPrefix := make([]byte, 3+b.Len())
|
||||||
|
copy(keyPrefix[3:], b.Bytes())
|
||||||
|
copy(keyPrefix[:3], openHeightPrefix)
|
||||||
|
|
||||||
|
var scratch [4]byte
|
||||||
|
byteOrder.PutUint32(scratch[:], channel.OpeningHeight)
|
||||||
|
return openChanBucket.Put(keyPrefix, scratch[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchChanOpenHeight(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := writeOutpoint(&b, channel.ChanID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPrefix := make([]byte, 3+b.Len())
|
||||||
|
copy(keyPrefix[3:], b.Bytes())
|
||||||
|
copy(keyPrefix[:3], openHeightPrefix)
|
||||||
|
|
||||||
|
openHeightBytes := openChanBucket.Get(keyPrefix)
|
||||||
|
channel.OpeningHeight = byteOrder.Uint32(openHeightBytes)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteChanOpenHeight(openChanBucket *bolt.Bucket, chanID []byte) error {
|
||||||
|
keyPrefix := make([]byte, 3+len(chanID))
|
||||||
|
copy(keyPrefix[3:], chanID)
|
||||||
|
copy(keyPrefix[:3], openHeightPrefix)
|
||||||
|
return openChanBucket.Delete(keyPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
func putChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
func putChannelIDs(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||||
// TODO(roasbeef): just pass in chanID everywhere for puts
|
// TODO(roasbeef): just pass in chanID everywhere for puts
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
|
|
@ -666,10 +666,23 @@ func TestFetchPendingChannels(t *testing.T) {
|
||||||
"got %v", 1, len(pendingChannels))
|
"got %v", 1, len(pendingChannels))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cdb.MarkChannelAsOpen(pendingChannels[0].ChanID); err != nil {
|
const openHeight = 100
|
||||||
|
err = cdb.MarkChannelAsOpen(pendingChannels[0].ChanID, openHeight)
|
||||||
|
if err != nil {
|
||||||
t.Fatalf("unable to mark channel as open: %v", err)
|
t.Fatalf("unable to mark channel as open: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next, we'll re-fetch the channel to ensure that the open height was
|
||||||
|
// properly set.
|
||||||
|
openChans, err := cdb.FetchAllChannels()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to fetch channels: %v", err)
|
||||||
|
}
|
||||||
|
if openChans[0].OpeningHeight != openHeight {
|
||||||
|
t.Fatalf("channel opening heights don't match: expected %v, "+
|
||||||
|
"got %v", openChans[0].OpeningHeight, openHeight)
|
||||||
|
}
|
||||||
|
|
||||||
pendingChannels, err = cdb.FetchPendingChannels()
|
pendingChannels, err = cdb.FetchPendingChannels()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to list pending channels: %v", err)
|
t.Fatalf("unable to list pending channels: %v", err)
|
||||||
|
@ -707,7 +720,8 @@ func TestFetchClosedChannels(t *testing.T) {
|
||||||
|
|
||||||
// Next, simulate the confirmation of the channel by marking it as
|
// Next, simulate the confirmation of the channel by marking it as
|
||||||
// pending within the database.
|
// pending within the database.
|
||||||
if err := cdb.MarkChannelAsOpen(state.ChanID); err != nil {
|
const openHeight = 100
|
||||||
|
if err := cdb.MarkChannelAsOpen(state.ChanID, openHeight); err != nil {
|
||||||
t.Fatalf("unable to mark channel as open: %v", err)
|
t.Fatalf("unable to mark channel as open: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -344,6 +344,7 @@ func fetchChannels(d *DB, pendingOnly bool) ([]*OpenChannel, error) {
|
||||||
return fmt.Errorf("unable to read channel for "+
|
return fmt.Errorf("unable to read channel for "+
|
||||||
"node_key=%x: %v", k, err)
|
"node_key=%x: %v", k, err)
|
||||||
}
|
}
|
||||||
|
// TODO(roasbeef): simplify
|
||||||
if pendingOnly {
|
if pendingOnly {
|
||||||
for _, channel := range nodeChannels {
|
for _, channel := range nodeChannels {
|
||||||
if channel.IsPending {
|
if channel.IsPending {
|
||||||
|
@ -361,16 +362,17 @@ func fetchChannels(d *DB, pendingOnly bool) ([]*OpenChannel, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkChannelAsOpen records the finalization of the funding process and marks
|
// MarkChannelAsOpen records the finalization of the funding process and marks
|
||||||
// a channel as available for use.
|
// a channel as available for use. Additionally the height in which this
|
||||||
func (d *DB) MarkChannelAsOpen(outpoint *wire.OutPoint) error {
|
// channel as opened will also be recorded within the database.
|
||||||
|
func (d *DB) MarkChannelAsOpen(outpoint *wire.OutPoint, openHeight uint32) error {
|
||||||
return d.Update(func(tx *bolt.Tx) error {
|
return d.Update(func(tx *bolt.Tx) error {
|
||||||
openChanBucket := tx.Bucket(openChannelBucket)
|
openChanBucket := tx.Bucket(openChannelBucket)
|
||||||
if openChanBucket == nil {
|
if openChanBucket == nil {
|
||||||
return ErrNoActiveChannels
|
return ErrNoActiveChannels
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the database key, which will consist of the IsPending
|
// Generate the database key, which will consist of the
|
||||||
// prefix followed by the channel's outpoint.
|
// IsPending prefix followed by the channel's outpoint.
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if err := writeOutpoint(&b, outpoint); err != nil {
|
if err := writeOutpoint(&b, outpoint); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -379,11 +381,20 @@ func (d *DB) MarkChannelAsOpen(outpoint *wire.OutPoint) error {
|
||||||
copy(keyPrefix[3:], b.Bytes())
|
copy(keyPrefix[3:], b.Bytes())
|
||||||
copy(keyPrefix[:3], isPendingPrefix)
|
copy(keyPrefix[:3], isPendingPrefix)
|
||||||
|
|
||||||
// For the database value, store a zero, since the channel is no
|
// For the database value, store a zero, since the channel is
|
||||||
// longer pending.
|
// no longer pending.
|
||||||
scratch := make([]byte, 2)
|
scratch := make([]byte, 4)
|
||||||
byteOrder.PutUint16(scratch, uint16(0))
|
byteOrder.PutUint16(scratch[:2], uint16(0))
|
||||||
return openChanBucket.Put(keyPrefix, scratch)
|
if err := openChanBucket.Put(keyPrefix, scratch[:2]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, we'll also store the opening height for this
|
||||||
|
// channel as well.
|
||||||
|
byteOrder.PutUint32(scratch, openHeight)
|
||||||
|
copy(keyPrefix[:3], openHeightPrefix)
|
||||||
|
|
||||||
|
return openChanBucket.Put(keyPrefix, scratch[:])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -922,7 +922,8 @@ func (f *fundingManager) waitForFundingConfirmation(completeChan *channeldb.Open
|
||||||
// Now that the channel has been fully confirmed, we'll mark it as open
|
// Now that the channel has been fully confirmed, we'll mark it as open
|
||||||
// within the database.
|
// within the database.
|
||||||
completeChan.IsPending = false
|
completeChan.IsPending = false
|
||||||
err = f.cfg.Wallet.ChannelDB.MarkChannelAsOpen(&fundingPoint)
|
err = f.cfg.Wallet.ChannelDB.MarkChannelAsOpen(&fundingPoint,
|
||||||
|
confDetails.BlockHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fndgLog.Errorf("error setting channel pending flag to false: "+
|
fndgLog.Errorf("error setting channel pending flag to false: "+
|
||||||
"%v", err)
|
"%v", err)
|
||||||
|
|
Loading…
Reference in New Issue