channeldb: store the funding transaction broadcast height for channels
This commit expands the field within the OpenChannel struct in order to start tracking the height that the funding transaction was initially broadcast. Other sub-systems within lnd can now use this data to give a more accurate height hint to the ChainNotifier, or to use during the funding workflow to decide if a channel should be forgotten after it fails to confirm for N blocks.
This commit is contained in:
parent
fb4121ba6c
commit
66ba2e862c
@ -70,7 +70,7 @@ var (
|
|||||||
satReceivedPrefix = []byte("srp")
|
satReceivedPrefix = []byte("srp")
|
||||||
commitFeePrefix = []byte("cfp")
|
commitFeePrefix = []byte("cfp")
|
||||||
isPendingPrefix = []byte("pdg")
|
isPendingPrefix = []byte("pdg")
|
||||||
openHeightPrefix = []byte("open-height-prefix")
|
confInfoPrefix = []byte("conf-info")
|
||||||
|
|
||||||
// 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")
|
||||||
@ -134,6 +134,12 @@ type OpenChannel struct {
|
|||||||
// marked open.
|
// marked open.
|
||||||
OpeningHeight uint32
|
OpeningHeight uint32
|
||||||
|
|
||||||
|
// FundingBroadcastHeight is the height in which the funding
|
||||||
|
// transaction was broadcast. This value can be used by higher level
|
||||||
|
// sub-systems to determine if a channel is stale and/or should have
|
||||||
|
// been confirmed before a certain height.
|
||||||
|
FundingBroadcastHeight 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
|
||||||
@ -353,10 +359,12 @@ func (c *OpenChannel) fullSync(tx *bolt.Tx) error {
|
|||||||
//
|
//
|
||||||
// TODO(roasbeef): addr param should eventually be a lnwire.NetAddress type
|
// TODO(roasbeef): addr param should eventually be a lnwire.NetAddress type
|
||||||
// that includes service bits.
|
// that includes service bits.
|
||||||
func (c *OpenChannel) SyncPending(addr *net.TCPAddr) error {
|
func (c *OpenChannel) SyncPending(addr *net.TCPAddr, pendingHeight uint32) error {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
|
c.FundingBroadcastHeight = pendingHeight
|
||||||
|
|
||||||
return c.Db.Update(func(tx *bolt.Tx) error {
|
return c.Db.Update(func(tx *bolt.Tx) error {
|
||||||
// First, sync all the persistent channel state to disk.
|
// First, sync all the persistent channel state to disk.
|
||||||
if err := c.fullSync(tx); err != nil {
|
if err := c.fullSync(tx); err != nil {
|
||||||
@ -1004,7 +1012,7 @@ 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 {
|
if err := putChanConfInfo(openChanBucket, channel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := putChanCommitFee(openChanBucket, channel); err != nil {
|
if err := putChanCommitFee(openChanBucket, channel); err != nil {
|
||||||
@ -1097,7 +1105,7 @@ 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 {
|
if err := fetchChanConfInfo(openChanBucket, channel); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err = fetchChanCommitFee(openChanBucket, channel); err != nil {
|
if err = fetchChanCommitFee(openChanBucket, channel); err != nil {
|
||||||
@ -1133,7 +1141,7 @@ 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 {
|
if err := deleteChanConfInfo(openChanBucket, channelID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := deleteChanCommitFee(openChanBucket, channelID); err != nil {
|
if err := deleteChanCommitFee(openChanBucket, channelID); err != nil {
|
||||||
@ -1503,41 +1511,45 @@ func fetchChanIsPending(openChanBucket *bolt.Bucket, channel *OpenChannel) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func putChanOpenHeight(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
func putChanConfInfo(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if err := writeOutpoint(&b, channel.ChanID); err != nil {
|
if err := writeOutpoint(&b, channel.ChanID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
keyPrefix := make([]byte, 3+b.Len())
|
keyPrefix := make([]byte, len(confInfoPrefix)+b.Len())
|
||||||
copy(keyPrefix[3:], b.Bytes())
|
copy(keyPrefix[:len(confInfoPrefix)], confInfoPrefix)
|
||||||
copy(keyPrefix[:3], openHeightPrefix)
|
copy(keyPrefix[len(confInfoPrefix):], b.Bytes())
|
||||||
|
|
||||||
|
// We store the conf info in the following format: broadcast || open.
|
||||||
|
var scratch [8]byte
|
||||||
|
byteOrder.PutUint32(scratch[:], channel.FundingBroadcastHeight)
|
||||||
|
byteOrder.PutUint32(scratch[4:], channel.OpeningHeight)
|
||||||
|
|
||||||
var scratch [4]byte
|
|
||||||
byteOrder.PutUint32(scratch[:], channel.OpeningHeight)
|
|
||||||
return openChanBucket.Put(keyPrefix, scratch[:])
|
return openChanBucket.Put(keyPrefix, scratch[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchChanOpenHeight(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
func fetchChanConfInfo(openChanBucket *bolt.Bucket, channel *OpenChannel) error {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
if err := writeOutpoint(&b, channel.ChanID); err != nil {
|
if err := writeOutpoint(&b, channel.ChanID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
keyPrefix := make([]byte, 3+b.Len())
|
keyPrefix := make([]byte, len(confInfoPrefix)+b.Len())
|
||||||
copy(keyPrefix[3:], b.Bytes())
|
copy(keyPrefix[:len(confInfoPrefix)], confInfoPrefix)
|
||||||
copy(keyPrefix[:3], openHeightPrefix)
|
copy(keyPrefix[len(confInfoPrefix):], b.Bytes())
|
||||||
|
|
||||||
openHeightBytes := openChanBucket.Get(keyPrefix)
|
confInfoBytes := openChanBucket.Get(keyPrefix)
|
||||||
channel.OpeningHeight = byteOrder.Uint32(openHeightBytes)
|
channel.FundingBroadcastHeight = byteOrder.Uint32(confInfoBytes[:4])
|
||||||
|
channel.OpeningHeight = byteOrder.Uint32(confInfoBytes[4:])
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteChanOpenHeight(openChanBucket *bolt.Bucket, chanID []byte) error {
|
func deleteChanConfInfo(openChanBucket *bolt.Bucket, chanID []byte) error {
|
||||||
keyPrefix := make([]byte, 3+len(chanID))
|
keyPrefix := make([]byte, len(confInfoPrefix)+len(chanID))
|
||||||
copy(keyPrefix[3:], chanID)
|
copy(keyPrefix[:len(confInfoPrefix)], confInfoPrefix)
|
||||||
copy(keyPrefix[:3], openHeightPrefix)
|
copy(keyPrefix[len(confInfoPrefix):], chanID)
|
||||||
return openChanBucket.Delete(keyPrefix)
|
return openChanBucket.Delete(keyPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,7 +654,8 @@ func TestFetchPendingChannels(t *testing.T) {
|
|||||||
Port: 18555,
|
Port: 18555,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := state.SyncPending(addr); err != nil {
|
const broadcastHeight = 99
|
||||||
|
if err := state.SyncPending(addr, broadcastHeight); err != nil {
|
||||||
t.Fatalf("unable to save and serialize channel state: %v", err)
|
t.Fatalf("unable to save and serialize channel state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,6 +669,14 @@ func TestFetchPendingChannels(t *testing.T) {
|
|||||||
"got %v", 1, len(pendingChannels))
|
"got %v", 1, len(pendingChannels))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The broadcast height of the pending channel should've been set
|
||||||
|
// properly.
|
||||||
|
if pendingChannels[0].FundingBroadcastHeight != broadcastHeight {
|
||||||
|
t.Fatalf("broadcast height mismatch: expected %v, got %v",
|
||||||
|
pendingChannels[0].FundingBroadcastHeight,
|
||||||
|
broadcastHeight)
|
||||||
|
}
|
||||||
|
|
||||||
const openHeight = 100
|
const openHeight = 100
|
||||||
err = cdb.MarkChannelAsOpen(pendingChannels[0].ChanID, openHeight)
|
err = cdb.MarkChannelAsOpen(pendingChannels[0].ChanID, openHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -684,6 +693,11 @@ func TestFetchPendingChannels(t *testing.T) {
|
|||||||
t.Fatalf("channel opening heights don't match: expected %v, "+
|
t.Fatalf("channel opening heights don't match: expected %v, "+
|
||||||
"got %v", openChans[0].OpeningHeight, openHeight)
|
"got %v", openChans[0].OpeningHeight, openHeight)
|
||||||
}
|
}
|
||||||
|
if openChans[0].FundingBroadcastHeight != broadcastHeight {
|
||||||
|
t.Fatalf("broadcast height mismatch: expected %v, got %v",
|
||||||
|
openChans[0].FundingBroadcastHeight,
|
||||||
|
broadcastHeight)
|
||||||
|
}
|
||||||
|
|
||||||
pendingChannels, err = cdb.FetchPendingChannels()
|
pendingChannels, err = cdb.FetchPendingChannels()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -716,7 +730,8 @@ func TestFetchClosedChannels(t *testing.T) {
|
|||||||
IP: net.ParseIP("127.0.0.1"),
|
IP: net.ParseIP("127.0.0.1"),
|
||||||
Port: 18555,
|
Port: 18555,
|
||||||
}
|
}
|
||||||
if err := state.SyncPending(addr); err != nil {
|
const broadcastHeight = 99
|
||||||
|
if err := state.SyncPending(addr, broadcastHeight); err != nil {
|
||||||
t.Fatalf("unable to save and serialize channel state: %v", err)
|
t.Fatalf("unable to save and serialize channel state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,10 +391,17 @@ func (d *DB) MarkChannelAsOpen(outpoint *wire.OutPoint, openHeight uint32) error
|
|||||||
|
|
||||||
// Finally, we'll also store the opening height for this
|
// Finally, we'll also store the opening height for this
|
||||||
// channel as well.
|
// channel as well.
|
||||||
byteOrder.PutUint32(scratch, openHeight)
|
confInfoKey := make([]byte, len(confInfoPrefix)+len(b.Bytes()))
|
||||||
copy(keyPrefix[:3], openHeightPrefix)
|
copy(confInfoKey[:len(confInfoPrefix)], confInfoPrefix)
|
||||||
|
copy(confInfoKey[len(confInfoPrefix):], b.Bytes())
|
||||||
|
|
||||||
return openChanBucket.Put(keyPrefix, scratch[:])
|
confInfoBytes := openChanBucket.Get(confInfoKey)
|
||||||
|
infoCopy := make([]byte, len(confInfoBytes))
|
||||||
|
copy(infoCopy[:], confInfoBytes)
|
||||||
|
|
||||||
|
byteOrder.PutUint32(infoCopy[4:], openHeight)
|
||||||
|
|
||||||
|
return openChanBucket.Put(confInfoKey, infoCopy)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user