mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-03 17:26:57 +01:00
channeldb: BigSize migration, store zero-conf, scid-alias bits
This introduces a BigSize migration that is used to expand the width of the ChannelStatus and ChannelType fields. Three channel "types" are added - ZeroConfBit, ScidAliasChanBit, and ScidAliasFeatureBit. ScidAliasChanBit denotes that the scid-alias channel type was negotiated for the channel. ScidAliasFeatureBit denotes that the scid-alias feature bit was negotiated during the *lifetime* of the channel. Several helper functions on the OpenChannel struct are exposed to aid callers from different packages. The RefreshShortChanID has been renamed to Refresh. A new function BroadcastHeight is used to guard access to the mutable FundingBroadcastHeight member. This prevents data races.
This commit is contained in:
parent
3ff8eb899c
commit
c9f5912601
13 changed files with 503 additions and 28 deletions
|
@ -177,7 +177,7 @@ func NewSingle(channel *channeldb.OpenChannel,
|
||||||
// to the channel ID so we can use that as height hint on restore.
|
// to the channel ID so we can use that as height hint on restore.
|
||||||
chanID := channel.ShortChanID()
|
chanID := channel.ShortChanID()
|
||||||
if chanID.BlockHeight == 0 {
|
if chanID.BlockHeight == 0 {
|
||||||
chanID.BlockHeight = channel.FundingBroadcastHeight
|
chanID.BlockHeight = channel.BroadcastHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
single := Single{
|
single := Single{
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
@ -53,6 +54,14 @@ var (
|
||||||
//
|
//
|
||||||
outpointBucket = []byte("outpoint-bucket")
|
outpointBucket = []byte("outpoint-bucket")
|
||||||
|
|
||||||
|
// chanIDBucket stores all of the 32-byte channel ID's we know about.
|
||||||
|
// These could be derived from outpointBucket, but it is more
|
||||||
|
// convenient to have these in their own bucket.
|
||||||
|
//
|
||||||
|
// chanID -> tlv stream.
|
||||||
|
//
|
||||||
|
chanIDBucket = []byte("chan-id-bucket")
|
||||||
|
|
||||||
// historicalChannelBucket stores all channels that have seen their
|
// historicalChannelBucket stores all channels that have seen their
|
||||||
// commitment tx confirm. All information from their previous open state
|
// commitment tx confirm. All information from their previous open state
|
||||||
// is retained.
|
// is retained.
|
||||||
|
@ -190,6 +199,10 @@ const (
|
||||||
// A tlv type used to serialize and deserialize the
|
// A tlv type used to serialize and deserialize the
|
||||||
// `InitialRemoteBalance` field.
|
// `InitialRemoteBalance` field.
|
||||||
initialRemoteBalanceType tlv.Type = 3
|
initialRemoteBalanceType tlv.Type = 3
|
||||||
|
|
||||||
|
// A tlv type definition used to serialize and deserialize the
|
||||||
|
// confirmed ShortChannelID for a zero-conf channel.
|
||||||
|
realScidType tlv.Type = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
// indexStatus is an enum-like type that describes what state the
|
// indexStatus is an enum-like type that describes what state the
|
||||||
|
@ -211,7 +224,7 @@ const (
|
||||||
// fee negotiation, channel closing, the format of HTLCs, etc. Structure-wise,
|
// fee negotiation, channel closing, the format of HTLCs, etc. Structure-wise,
|
||||||
// a ChannelType is a bit field, with each bit denoting a modification from the
|
// a ChannelType is a bit field, with each bit denoting a modification from the
|
||||||
// base channel type of single funder.
|
// base channel type of single funder.
|
||||||
type ChannelType uint8
|
type ChannelType uint64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// NOTE: iota isn't used here for this enum needs to be stable
|
// NOTE: iota isn't used here for this enum needs to be stable
|
||||||
|
@ -254,6 +267,17 @@ const (
|
||||||
// period of time, constraining every output that pays to the channel
|
// period of time, constraining every output that pays to the channel
|
||||||
// initiator with an additional CLTV of the lease maturity.
|
// initiator with an additional CLTV of the lease maturity.
|
||||||
LeaseExpirationBit ChannelType = 1 << 6
|
LeaseExpirationBit ChannelType = 1 << 6
|
||||||
|
|
||||||
|
// ZeroConfBit indicates that the channel is a zero-conf channel.
|
||||||
|
ZeroConfBit ChannelType = 1 << 7
|
||||||
|
|
||||||
|
// ScidAliasChanBit indicates that the channel has negotiated the
|
||||||
|
// scid-alias channel type.
|
||||||
|
ScidAliasChanBit ChannelType = 1 << 8
|
||||||
|
|
||||||
|
// ScidAliasFeatureBit indicates that the scid-alias feature bit was
|
||||||
|
// negotiated during the lifetime of this channel.
|
||||||
|
ScidAliasFeatureBit ChannelType = 1 << 9
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsSingleFunder returns true if the channel type if one of the known single
|
// IsSingleFunder returns true if the channel type if one of the known single
|
||||||
|
@ -303,6 +327,22 @@ func (c ChannelType) HasLeaseExpiration() bool {
|
||||||
return c&LeaseExpirationBit == LeaseExpirationBit
|
return c&LeaseExpirationBit == LeaseExpirationBit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasZeroConf returns true if the channel is a zero-conf channel.
|
||||||
|
func (c ChannelType) HasZeroConf() bool {
|
||||||
|
return c&ZeroConfBit == ZeroConfBit
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasScidAliasChan returns true if the scid-alias channel type was negotiated.
|
||||||
|
func (c ChannelType) HasScidAliasChan() bool {
|
||||||
|
return c&ScidAliasChanBit == ScidAliasChanBit
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasScidAliasFeature returns true if the scid-alias feature bit was
|
||||||
|
// negotiated during the lifetime of this channel.
|
||||||
|
func (c ChannelType) HasScidAliasFeature() bool {
|
||||||
|
return c&ScidAliasFeatureBit == ScidAliasFeatureBit
|
||||||
|
}
|
||||||
|
|
||||||
// ChannelConstraints represents a set of constraints meant to allow a node to
|
// ChannelConstraints represents a set of constraints meant to allow a node to
|
||||||
// limit their exposure, enact flow control and ensure that all HTLCs are
|
// limit their exposure, enact flow control and ensure that all HTLCs are
|
||||||
// economically relevant. This struct will be mirrored for both sides of the
|
// economically relevant. This struct will be mirrored for both sides of the
|
||||||
|
@ -476,7 +516,7 @@ type ChannelCommitment struct {
|
||||||
|
|
||||||
// ChannelStatus is a bit vector used to indicate whether an OpenChannel is in
|
// ChannelStatus is a bit vector used to indicate whether an OpenChannel is in
|
||||||
// the default usable state, or a state where it shouldn't be used.
|
// the default usable state, or a state where it shouldn't be used.
|
||||||
type ChannelStatus uint8
|
type ChannelStatus uint64
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ChanStatusDefault is the normal state of an open channel.
|
// ChanStatusDefault is the normal state of an open channel.
|
||||||
|
@ -604,6 +644,9 @@ type OpenChannel struct {
|
||||||
// ShortChannelID encodes the exact location in the chain in which the
|
// ShortChannelID encodes the exact location in the chain in which the
|
||||||
// channel was initially confirmed. This includes: the block height,
|
// channel was initially confirmed. This includes: the block height,
|
||||||
// transaction index, and the output within the target transaction.
|
// transaction index, and the output within the target transaction.
|
||||||
|
//
|
||||||
|
// If IsZeroConf(), then this will the "base" (very first) ALIAS scid
|
||||||
|
// and the confirmed SCID will be stored in ConfirmedScid.
|
||||||
ShortChannelID lnwire.ShortChannelID
|
ShortChannelID lnwire.ShortChannelID
|
||||||
|
|
||||||
// IsPending indicates whether a channel's funding transaction has been
|
// IsPending indicates whether a channel's funding transaction has been
|
||||||
|
@ -739,6 +782,11 @@ type OpenChannel struct {
|
||||||
// have private key isolation from lnd.
|
// have private key isolation from lnd.
|
||||||
RevocationKeyLocator keychain.KeyLocator
|
RevocationKeyLocator keychain.KeyLocator
|
||||||
|
|
||||||
|
// confirmedScid is the confirmed ShortChannelID for a zero-conf
|
||||||
|
// channel. If the channel is unconfirmed, then this will be the
|
||||||
|
// default ShortChannelID. This is only set for zero-conf channels.
|
||||||
|
confirmedScid lnwire.ShortChannelID
|
||||||
|
|
||||||
// TODO(roasbeef): eww
|
// TODO(roasbeef): eww
|
||||||
Db *ChannelStateDB
|
Db *ChannelStateDB
|
||||||
|
|
||||||
|
@ -755,6 +803,50 @@ func (c *OpenChannel) ShortChanID() lnwire.ShortChannelID {
|
||||||
return c.ShortChannelID
|
return c.ShortChannelID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ZeroConfRealScid returns the zero-conf channel's confirmed scid. This should
|
||||||
|
// only be called if IsZeroConf returns true.
|
||||||
|
func (c *OpenChannel) ZeroConfRealScid() lnwire.ShortChannelID {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
return c.confirmedScid
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZeroConfConfirmed returns whether the zero-conf channel has confirmed. This
|
||||||
|
// should only be called if IsZeroConf returns true.
|
||||||
|
func (c *OpenChannel) ZeroConfConfirmed() bool {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
return c.confirmedScid != hop.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZeroConf returns whether the option_zeroconf channel type was negotiated.
|
||||||
|
func (c *OpenChannel) IsZeroConf() bool {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
return c.ChanType.HasZeroConf()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsOptionScidAlias returns whether the option_scid_alias channel type was
|
||||||
|
// negotiated.
|
||||||
|
func (c *OpenChannel) IsOptionScidAlias() bool {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
return c.ChanType.HasScidAliasChan()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NegotiatedAliasFeature returns whether the option-scid-alias feature bit was
|
||||||
|
// negotiated.
|
||||||
|
func (c *OpenChannel) NegotiatedAliasFeature() bool {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
return c.ChanType.HasScidAliasFeature()
|
||||||
|
}
|
||||||
|
|
||||||
// ChanStatus returns the current ChannelStatus of this channel.
|
// ChanStatus returns the current ChannelStatus of this channel.
|
||||||
func (c *OpenChannel) ChanStatus() ChannelStatus {
|
func (c *OpenChannel) ChanStatus() ChannelStatus {
|
||||||
c.RLock()
|
c.RLock()
|
||||||
|
@ -801,13 +893,25 @@ func (c *OpenChannel) hasChanStatus(status ChannelStatus) bool {
|
||||||
return c.chanStatus&status == status
|
return c.chanStatus&status == status
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshShortChanID updates the in-memory channel state using the latest
|
// BroadcastHeight returns the height at which the funding tx was broadcast.
|
||||||
// value observed on disk.
|
func (c *OpenChannel) BroadcastHeight() uint32 {
|
||||||
//
|
c.RLock()
|
||||||
// TODO: the name of this function should be changed to reflect the fact that
|
defer c.RUnlock()
|
||||||
// it is not only refreshing the short channel id but all the channel state.
|
|
||||||
// maybe Refresh/Reload?
|
return c.FundingBroadcastHeight
|
||||||
func (c *OpenChannel) RefreshShortChanID() error {
|
}
|
||||||
|
|
||||||
|
// SetBroadcastHeight sets the FundingBroadcastHeight.
|
||||||
|
func (c *OpenChannel) SetBroadcastHeight(height uint32) {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
c.FundingBroadcastHeight = height
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh updates the in-memory channel state using the latest state observed
|
||||||
|
// on disk.
|
||||||
|
func (c *OpenChannel) Refresh() error {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
|
@ -825,6 +929,19 @@ func (c *OpenChannel) RefreshShortChanID() error {
|
||||||
return fmt.Errorf("unable to fetch chan info: %v", err)
|
return fmt.Errorf("unable to fetch chan info: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also populate the channel's commitment states for both sides
|
||||||
|
// of the channel.
|
||||||
|
if err := fetchChanCommitments(chanBucket, c); err != nil {
|
||||||
|
return fmt.Errorf("unable to fetch chan commitments: "+
|
||||||
|
"%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also retrieve the current revocation state.
|
||||||
|
if err := fetchChanRevocationState(chanBucket, c); err != nil {
|
||||||
|
return fmt.Errorf("unable to fetch chan revocations: "+
|
||||||
|
"%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}, func() {})
|
}, func() {})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -931,6 +1048,7 @@ func fetchChanBucketRw(tx kvdb.RwTx, nodeKey *btcec.PublicKey,
|
||||||
func (c *OpenChannel) fullSync(tx kvdb.RwTx) error {
|
func (c *OpenChannel) fullSync(tx kvdb.RwTx) error {
|
||||||
// Fetch the outpoint bucket and check if the outpoint already exists.
|
// Fetch the outpoint bucket and check if the outpoint already exists.
|
||||||
opBucket := tx.ReadWriteBucket(outpointBucket)
|
opBucket := tx.ReadWriteBucket(outpointBucket)
|
||||||
|
cidBucket := tx.ReadWriteBucket(chanIDBucket)
|
||||||
|
|
||||||
var chanPointBuf bytes.Buffer
|
var chanPointBuf bytes.Buffer
|
||||||
if err := writeOutpoint(&chanPointBuf, &c.FundingOutpoint); err != nil {
|
if err := writeOutpoint(&chanPointBuf, &c.FundingOutpoint); err != nil {
|
||||||
|
@ -942,6 +1060,11 @@ func (c *OpenChannel) fullSync(tx kvdb.RwTx) error {
|
||||||
return ErrChanAlreadyExists
|
return ErrChanAlreadyExists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cid := lnwire.NewChanIDFromOutPoint(&c.FundingOutpoint)
|
||||||
|
if cidBucket.Get(cid[:]) != nil {
|
||||||
|
return ErrChanAlreadyExists
|
||||||
|
}
|
||||||
|
|
||||||
status := uint8(outpointOpen)
|
status := uint8(outpointOpen)
|
||||||
|
|
||||||
// Write the status of this outpoint as the first entry in a tlv
|
// Write the status of this outpoint as the first entry in a tlv
|
||||||
|
@ -962,6 +1085,10 @@ func (c *OpenChannel) fullSync(tx kvdb.RwTx) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cidBucket.Put(cid[:], []byte{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// First fetch the top level bucket which stores all data related to
|
// First fetch the top level bucket which stores all data related to
|
||||||
// current, active channels.
|
// current, active channels.
|
||||||
openChanBucket, err := tx.CreateTopLevelBucket(openChannelBucket)
|
openChanBucket, err := tx.CreateTopLevelBucket(openChannelBucket)
|
||||||
|
@ -1035,6 +1162,71 @@ func (c *OpenChannel) MarkAsOpen(openLoc lnwire.ShortChannelID) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkRealScid marks the zero-conf channel's confirmed ShortChannelID. This
|
||||||
|
// should only be done if IsZeroConf returns true.
|
||||||
|
func (c *OpenChannel) MarkRealScid(realScid lnwire.ShortChannelID) error {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
if err := kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
|
||||||
|
chanBucket, err := fetchChanBucketRw(
|
||||||
|
tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := fetchOpenChannel(
|
||||||
|
chanBucket, &c.FundingOutpoint,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.confirmedScid = realScid
|
||||||
|
|
||||||
|
return putOpenChannel(chanBucket, channel)
|
||||||
|
}, func() {}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.confirmedScid = realScid
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkScidAliasNegotiated adds ScidAliasFeatureBit to ChanType in-memory and
|
||||||
|
// in the database.
|
||||||
|
func (c *OpenChannel) MarkScidAliasNegotiated() error {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
if err := kvdb.Update(c.Db.backend, func(tx kvdb.RwTx) error {
|
||||||
|
chanBucket, err := fetchChanBucketRw(
|
||||||
|
tx, c.IdentityPub, &c.FundingOutpoint, c.ChainHash,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := fetchOpenChannel(
|
||||||
|
chanBucket, &c.FundingOutpoint,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.ChanType |= ScidAliasFeatureBit
|
||||||
|
return putOpenChannel(chanBucket, channel)
|
||||||
|
}, func() {}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ChanType |= ScidAliasFeatureBit
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// MarkDataLoss marks sets the channel status to LocalDataLoss and stores the
|
// MarkDataLoss marks sets the channel status to LocalDataLoss and stores the
|
||||||
// passed commitPoint for use to retrieve funds in case the remote force closes
|
// passed commitPoint for use to retrieve funds in case the remote force closes
|
||||||
// the channel.
|
// the channel.
|
||||||
|
@ -1101,6 +1293,22 @@ func (c *OpenChannel) MarkBorked() error {
|
||||||
return c.putChanStatus(ChanStatusBorked)
|
return c.putChanStatus(ChanStatusBorked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecondCommitmentPoint returns the second per-commitment-point for use in the
|
||||||
|
// funding_locked message.
|
||||||
|
func (c *OpenChannel) SecondCommitmentPoint() (*btcec.PublicKey, error) {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
// Since we start at commitment height = 0, the second per commitment
|
||||||
|
// point is actually at the 1st index.
|
||||||
|
revocation, err := c.RevocationProducer.AtIndex(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.ComputeCommitmentPoint(revocation[:]), nil
|
||||||
|
}
|
||||||
|
|
||||||
// ChanSyncMsg returns the ChannelReestablish message that should be sent upon
|
// ChanSyncMsg returns the ChannelReestablish message that should be sent upon
|
||||||
// reconnection with the remote peer that we're maintaining this channel with.
|
// reconnection with the remote peer that we're maintaining this channel with.
|
||||||
// The information contained within this message is necessary to re-sync our
|
// The information contained within this message is necessary to re-sync our
|
||||||
|
@ -3095,7 +3303,24 @@ func (c *OpenChannel) AbsoluteThawHeight() (uint32, error) {
|
||||||
return 0, errors.New("cannot use relative thaw " +
|
return 0, errors.New("cannot use relative thaw " +
|
||||||
"height for unconfirmed channel")
|
"height for unconfirmed channel")
|
||||||
}
|
}
|
||||||
return c.ShortChannelID.BlockHeight + c.ThawHeight, nil
|
|
||||||
|
// For non-zero-conf channels, this is the base height to use.
|
||||||
|
blockHeightBase := c.ShortChannelID.BlockHeight
|
||||||
|
|
||||||
|
// If this is a zero-conf channel, the ShortChannelID will be
|
||||||
|
// an alias.
|
||||||
|
if c.IsZeroConf() {
|
||||||
|
if !c.ZeroConfConfirmed() {
|
||||||
|
return 0, errors.New("cannot use relative " +
|
||||||
|
"height for unconfirmed zero-conf " +
|
||||||
|
"channel")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the confirmed SCID's BlockHeight.
|
||||||
|
blockHeightBase = c.confirmedScid.BlockHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockHeightBase + c.ThawHeight, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.ThawHeight, nil
|
return c.ThawHeight, nil
|
||||||
|
@ -3325,6 +3550,7 @@ func putChanInfo(chanBucket kvdb.RwBucket, channel *OpenChannel) error {
|
||||||
tlv.MakePrimitiveRecord(
|
tlv.MakePrimitiveRecord(
|
||||||
initialRemoteBalanceType, &remoteBalance,
|
initialRemoteBalanceType, &remoteBalance,
|
||||||
),
|
),
|
||||||
|
MakeScidRecord(realScidType, &channel.confirmedScid),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -3541,6 +3767,7 @@ func fetchChanInfo(chanBucket kvdb.RBucket, channel *OpenChannel) error {
|
||||||
tlv.MakePrimitiveRecord(
|
tlv.MakePrimitiveRecord(
|
||||||
initialRemoteBalanceType, &remoteBalance,
|
initialRemoteBalanceType, &remoteBalance,
|
||||||
),
|
),
|
||||||
|
MakeScidRecord(realScidType, &channel.confirmedScid),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -3744,3 +3971,12 @@ func DKeyLocator(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
|
||||||
func MakeKeyLocRecord(typ tlv.Type, keyLoc *keychain.KeyLocator) tlv.Record {
|
func MakeKeyLocRecord(typ tlv.Type, keyLoc *keychain.KeyLocator) tlv.Record {
|
||||||
return tlv.MakeStaticRecord(typ, keyLoc, 8, EKeyLocator, DKeyLocator)
|
return tlv.MakeStaticRecord(typ, keyLoc, 8, EKeyLocator, DKeyLocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeScidRecord creates a Record out of a ShortChannelID using the passed
|
||||||
|
// Type and the EShortChannelID and DShortChannelID functions. The size will
|
||||||
|
// always be 8 for the ShortChannelID.
|
||||||
|
func MakeScidRecord(typ tlv.Type, scid *lnwire.ShortChannelID) tlv.Record {
|
||||||
|
return tlv.MakeStaticRecord(
|
||||||
|
typ, scid, 8, lnwire.EShortChannelID, lnwire.DShortChannelID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -1148,10 +1148,10 @@ func TestFetchWaitingCloseChannels(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRefreshShortChanID asserts that RefreshShortChanID updates the in-memory
|
// TestRefresh asserts that Refresh updates the in-memory state of another
|
||||||
// state of another OpenChannel to reflect a preceding call to MarkOpen on a
|
// OpenChannel to reflect a preceding call to MarkOpen on a different
|
||||||
// different OpenChannel.
|
// OpenChannel.
|
||||||
func TestRefreshShortChanID(t *testing.T) {
|
func TestRefresh(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
fullDB, cleanUp, err := MakeTestDB()
|
fullDB, cleanUp, err := MakeTestDB()
|
||||||
|
@ -1209,8 +1209,8 @@ func TestRefreshShortChanID(t *testing.T) {
|
||||||
state.Packager.(*ChannelPackager).source)
|
state.Packager.(*ChannelPackager).source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, refresh the short channel ID of the pending channel.
|
// Now, refresh the state of the pending channel.
|
||||||
err = pendingChannel.RefreshShortChanID()
|
err = pendingChannel.Refresh()
|
||||||
require.NoError(t, err, "unable to refresh short_chan_id")
|
require.NoError(t, err, "unable to refresh short_chan_id")
|
||||||
|
|
||||||
// This should result in both OpenChannel's now having the same
|
// This should result in both OpenChannel's now having the same
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/lightningnetwork/lnd/keychain"
|
"github.com/lightningnetwork/lnd/keychain"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/shachain"
|
"github.com/lightningnetwork/lnd/shachain"
|
||||||
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// writeOutpoint writes an outpoint to the passed writer using the minimal
|
// writeOutpoint writes an outpoint to the passed writer using the minimal
|
||||||
|
@ -85,7 +86,8 @@ func WriteElement(w io.Writer, element interface{}) error {
|
||||||
|
|
||||||
return binary.Write(w, byteOrder, false)
|
return binary.Write(w, byteOrder, false)
|
||||||
case ChannelType:
|
case ChannelType:
|
||||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
var buf [8]byte
|
||||||
|
if err := tlv.WriteVarInt(w, uint64(e), &buf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +196,8 @@ func WriteElement(w io.Writer, element interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
case ChannelStatus:
|
case ChannelStatus:
|
||||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
var buf [8]byte
|
||||||
|
if err := tlv.WriteVarInt(w, uint64(e), &buf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,10 +273,14 @@ func ReadElement(r io.Reader, element interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ChannelType:
|
case *ChannelType:
|
||||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
var buf [8]byte
|
||||||
|
ctype, err := tlv.ReadVarInt(r, &buf)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*e = ChannelType(ctype)
|
||||||
|
|
||||||
case *chainhash.Hash:
|
case *chainhash.Hash:
|
||||||
if _, err := io.ReadFull(r, e[:]); err != nil {
|
if _, err := io.ReadFull(r, e[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -419,10 +426,14 @@ func ReadElement(r io.Reader, element interface{}) error {
|
||||||
*e = msg
|
*e = msg
|
||||||
|
|
||||||
case *ChannelStatus:
|
case *ChannelStatus:
|
||||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
var buf [8]byte
|
||||||
|
status, err := tlv.ReadVarInt(r, &buf)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*e = ChannelStatus(status)
|
||||||
|
|
||||||
case *ClosureType:
|
case *ClosureType:
|
||||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/lightningnetwork/lnd/channeldb/migration25"
|
"github.com/lightningnetwork/lnd/channeldb/migration25"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/migration26"
|
"github.com/lightningnetwork/lnd/channeldb/migration26"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/migration27"
|
"github.com/lightningnetwork/lnd/channeldb/migration27"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb/migration29"
|
||||||
"github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
|
"github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
|
||||||
"github.com/lightningnetwork/lnd/clock"
|
"github.com/lightningnetwork/lnd/clock"
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
@ -226,6 +227,14 @@ var (
|
||||||
number: 27,
|
number: 27,
|
||||||
migration: migration27.MigrateHistoricalBalances,
|
migration: migration27.MigrateHistoricalBalances,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
number: 28,
|
||||||
|
migration: mig.CreateTLB(chanIDBucket),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: 29,
|
||||||
|
migration: migration29.MigrateChanID,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Big endian is the preferred byte order, due to cursor scans over
|
// Big endian is the preferred byte order, due to cursor scans over
|
||||||
|
@ -352,6 +361,7 @@ var dbTopLevelBuckets = [][]byte{
|
||||||
metaBucket,
|
metaBucket,
|
||||||
closeSummaryBucket,
|
closeSummaryBucket,
|
||||||
outpointBucket,
|
outpointBucket,
|
||||||
|
chanIDBucket,
|
||||||
historicalChannelBucket,
|
historicalChannelBucket,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
66
channeldb/migration29/codec.go
Normal file
66
channeldb/migration29/codec.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package migration29
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
byteOrder = binary.BigEndian
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChannelID is a series of 32-bytes that uniquely identifies all channels
|
||||||
|
// within the network. The ChannelID is computed using the outpoint of the
|
||||||
|
// funding transaction (the txid, and output index). Given a funding output the
|
||||||
|
// ChannelID can be calculated by XOR'ing the big-endian serialization of the
|
||||||
|
// txid and the big-endian serialization of the output index, truncated to
|
||||||
|
// 2 bytes.
|
||||||
|
type ChannelID [32]byte
|
||||||
|
|
||||||
|
// String returns the string representation of the ChannelID. This is just the
|
||||||
|
// hex string encoding of the ChannelID itself.
|
||||||
|
func (c ChannelID) String() string {
|
||||||
|
return hex.EncodeToString(c[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewChanIDFromOutPoint converts a target OutPoint into a ChannelID that is
|
||||||
|
// usable within the network. In order to convert the OutPoint into a ChannelID,
|
||||||
|
// we XOR the lower 2-bytes of the txid within the OutPoint with the big-endian
|
||||||
|
// serialization of the Index of the OutPoint, truncated to 2-bytes.
|
||||||
|
func NewChanIDFromOutPoint(op *wire.OutPoint) ChannelID {
|
||||||
|
// First we'll copy the txid of the outpoint into our channel ID slice.
|
||||||
|
var cid ChannelID
|
||||||
|
copy(cid[:], op.Hash[:])
|
||||||
|
|
||||||
|
// With the txid copied over, we'll now XOR the lower 2-bytes of the
|
||||||
|
// partial channelID with big-endian serialization of output index.
|
||||||
|
xorTxid(&cid, uint16(op.Index))
|
||||||
|
|
||||||
|
return cid
|
||||||
|
}
|
||||||
|
|
||||||
|
// xorTxid performs the transformation needed to transform an OutPoint into a
|
||||||
|
// ChannelID. To do this, we expect the cid parameter to contain the txid
|
||||||
|
// unaltered and the outputIndex to be the output index
|
||||||
|
func xorTxid(cid *ChannelID, outputIndex uint16) {
|
||||||
|
var buf [2]byte
|
||||||
|
binary.BigEndian.PutUint16(buf[:], outputIndex)
|
||||||
|
|
||||||
|
cid[30] ^= buf[0]
|
||||||
|
cid[31] ^= buf[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// readOutpoint reads an outpoint from the passed reader.
|
||||||
|
func readOutpoint(r io.Reader, o *wire.OutPoint) error {
|
||||||
|
if _, err := io.ReadFull(r, o.Hash[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, byteOrder, &o.Index); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
12
channeldb/migration29/log.go
Normal file
12
channeldb/migration29/log.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package migration29
|
||||||
|
|
||||||
|
import "github.com/btcsuite/btclog"
|
||||||
|
|
||||||
|
// log is a logger that is initialized as disabled. This means the package will
|
||||||
|
// not perform any logging by default until a logger is set.
|
||||||
|
var log = btclog.Disabled
|
||||||
|
|
||||||
|
// UseLogger uses a specific Logger to output package logging info.
|
||||||
|
func UseLogger(logger btclog.Logger) {
|
||||||
|
log = logger
|
||||||
|
}
|
72
channeldb/migration29/migration.go
Normal file
72
channeldb/migration29/migration.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package migration29
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// outpointBucket is the bucket that stores the set of outpoints we
|
||||||
|
// know about.
|
||||||
|
outpointBucket = []byte("outpoint-bucket")
|
||||||
|
|
||||||
|
// chanIDBucket is the bucket that stores the set of ChannelID's we
|
||||||
|
// know about.
|
||||||
|
chanIDBucket = []byte("chan-id-bucket")
|
||||||
|
)
|
||||||
|
|
||||||
|
// MigrateChanID populates the ChannelID index by using the set of outpoints
|
||||||
|
// retrieved from the outpoint bucket.
|
||||||
|
func MigrateChanID(tx kvdb.RwTx) error {
|
||||||
|
log.Info("Populating ChannelID index")
|
||||||
|
|
||||||
|
// First we'll retrieve the set of outpoints we know about.
|
||||||
|
ops, err := fetchOutPoints(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return populateChanIDIndex(tx, ops)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchOutPoints loops through the outpointBucket and returns each stored
|
||||||
|
// outpoint.
|
||||||
|
func fetchOutPoints(tx kvdb.RwTx) ([]*wire.OutPoint, error) {
|
||||||
|
var ops []*wire.OutPoint
|
||||||
|
|
||||||
|
bucket := tx.ReadBucket(outpointBucket)
|
||||||
|
|
||||||
|
err := bucket.ForEach(func(k, _ []byte) error {
|
||||||
|
var op wire.OutPoint
|
||||||
|
r := bytes.NewReader(k)
|
||||||
|
if err := readOutpoint(r, &op); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ops = append(ops, &op)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ops, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// populateChanIDIndex uses the set of retrieved outpoints and populates the
|
||||||
|
// ChannelID index.
|
||||||
|
func populateChanIDIndex(tx kvdb.RwTx, ops []*wire.OutPoint) error {
|
||||||
|
bucket := tx.ReadWriteBucket(chanIDBucket)
|
||||||
|
|
||||||
|
for _, op := range ops {
|
||||||
|
chanID := NewChanIDFromOutPoint(op)
|
||||||
|
|
||||||
|
if err := bucket.Put(chanID[:], []byte{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
67
channeldb/migration29/migration_test.go
Normal file
67
channeldb/migration29/migration_test.go
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package migration29
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb/migtest"
|
||||||
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
hexStr = migtest.Hex
|
||||||
|
|
||||||
|
outpoint1 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec58ce90fb463ad")
|
||||||
|
outpoint2 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec58ce952d6c6c7")
|
||||||
|
|
||||||
|
chanID1 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec5ef44")
|
||||||
|
chanID2 = hexStr("81b637d8fcd2c6da6859e6963113a1170de793e4b725b84d1e0b4cf99ec54a2e")
|
||||||
|
|
||||||
|
// These tlv streams are used to populate the outpoint bucket at the
|
||||||
|
// start of the test.
|
||||||
|
tlvOutpointOpen = hexStr("000100")
|
||||||
|
tlvOutpointClosed = hexStr("000101")
|
||||||
|
|
||||||
|
// outpointData is used to populate the outpoint bucket.
|
||||||
|
outpointData = map[string]interface{}{
|
||||||
|
outpoint1: tlvOutpointOpen,
|
||||||
|
outpoint2: tlvOutpointClosed,
|
||||||
|
}
|
||||||
|
|
||||||
|
// chanIDBefore is the ChannelID bucket before the migration.
|
||||||
|
chanIDBefore = map[string]interface{}{}
|
||||||
|
|
||||||
|
// post is the expected data in the ChannelID bucket after the
|
||||||
|
// migration.
|
||||||
|
post = map[string]interface{}{
|
||||||
|
chanID1: "",
|
||||||
|
chanID2: "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestMigrateChannelIDIndex asserts that the ChannelID index is properly
|
||||||
|
// populated.
|
||||||
|
func TestMigrateChannelIDIndex(t *testing.T) {
|
||||||
|
// Prime the database with the populated outpoint bucket. We create the
|
||||||
|
// ChannelID bucket since the prior migration creates it anyways.
|
||||||
|
before := func(tx kvdb.RwTx) error {
|
||||||
|
err := migtest.RestoreDB(tx, outpointBucket, outpointData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return migtest.RestoreDB(tx, chanIDBucket, chanIDBefore)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After the migration, ensure that the ChannelID bucket is properly
|
||||||
|
// populated.
|
||||||
|
after := func(tx kvdb.RwTx) error {
|
||||||
|
err := migtest.VerifyDB(tx, outpointBucket, outpointData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return migtest.VerifyDB(tx, chanIDBucket, post)
|
||||||
|
}
|
||||||
|
|
||||||
|
migtest.ApplyMigration(t, before, after, MigrateChanID, false)
|
||||||
|
}
|
|
@ -243,7 +243,7 @@ func (c *chanDBRestorer) RestoreChansFromSingles(backups ...chanbackup.Single) e
|
||||||
// funding broadcast height to a reasonable value that we
|
// funding broadcast height to a reasonable value that we
|
||||||
// determined earlier.
|
// determined earlier.
|
||||||
case channel.ShortChanID().BlockHeight == 0:
|
case channel.ShortChanID().BlockHeight == 0:
|
||||||
channel.FundingBroadcastHeight = firstChanHeight
|
channel.SetBroadcastHeight(firstChanHeight)
|
||||||
|
|
||||||
// Fallback case 2: It is extremely unlikely at this point that
|
// Fallback case 2: It is extremely unlikely at this point that
|
||||||
// a channel we are trying to restore has a coinbase funding TX.
|
// a channel we are trying to restore has a coinbase funding TX.
|
||||||
|
@ -255,7 +255,7 @@ func (c *chanDBRestorer) RestoreChansFromSingles(backups ...chanbackup.Single) e
|
||||||
// unconfirmed one here.
|
// unconfirmed one here.
|
||||||
case channel.ShortChannelID.TxIndex == 0:
|
case channel.ShortChannelID.TxIndex == 0:
|
||||||
broadcastHeight := channel.ShortChannelID.BlockHeight
|
broadcastHeight := channel.ShortChannelID.BlockHeight
|
||||||
channel.FundingBroadcastHeight = broadcastHeight
|
channel.SetBroadcastHeight(broadcastHeight)
|
||||||
channel.ShortChannelID.BlockHeight = 0
|
channel.ShortChannelID.BlockHeight = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ func (c *chainWatcher) Start() error {
|
||||||
// at.
|
// at.
|
||||||
heightHint := c.cfg.chanState.ShortChanID().BlockHeight
|
heightHint := c.cfg.chanState.ShortChanID().BlockHeight
|
||||||
if heightHint == 0 {
|
if heightHint == 0 {
|
||||||
heightHint = chanState.FundingBroadcastHeight
|
heightHint = chanState.BroadcastHeight()
|
||||||
}
|
}
|
||||||
|
|
||||||
localKey := chanState.LocalChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
localKey := chanState.LocalChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
||||||
|
|
|
@ -2306,7 +2306,7 @@ func (f *Manager) waitForFundingConfirmation(
|
||||||
numConfs := uint32(completeChan.NumConfsRequired)
|
numConfs := uint32(completeChan.NumConfsRequired)
|
||||||
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(
|
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(
|
||||||
&txid, fundingScript, numConfs,
|
&txid, fundingScript, numConfs,
|
||||||
completeChan.FundingBroadcastHeight,
|
completeChan.BroadcastHeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to register for confirmation of "+
|
log.Errorf("Unable to register for confirmation of "+
|
||||||
|
@ -2392,7 +2392,8 @@ func (f *Manager) waitForTimeout(completeChan *channeldb.OpenChannel,
|
||||||
defer epochClient.Cancel()
|
defer epochClient.Cancel()
|
||||||
|
|
||||||
// On block maxHeight we will cancel the funding confirmation wait.
|
// On block maxHeight we will cancel the funding confirmation wait.
|
||||||
maxHeight := completeChan.FundingBroadcastHeight + maxWaitNumBlocksFundingConf
|
broadcastHeight := completeChan.BroadcastHeight()
|
||||||
|
maxHeight := broadcastHeight + maxWaitNumBlocksFundingConf
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case epoch, ok := <-epochClient.Epochs:
|
case epoch, ok := <-epochClient.Epochs:
|
||||||
|
@ -2738,7 +2739,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
|
||||||
// funding transaction reaches at least 6 confirmations.
|
// funding transaction reaches at least 6 confirmations.
|
||||||
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(
|
confNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(
|
||||||
&txid, fundingScript, numConfs,
|
&txid, fundingScript, numConfs,
|
||||||
completeChan.FundingBroadcastHeight,
|
completeChan.BroadcastHeight(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to register for "+
|
return fmt.Errorf("unable to register for "+
|
||||||
|
|
|
@ -2243,7 +2243,7 @@ func (l *channelLink) UpdateShortChanID() (lnwire.ShortChannelID, error) {
|
||||||
// Refresh the channel state's short channel ID by loading it from disk.
|
// Refresh the channel state's short channel ID by loading it from disk.
|
||||||
// This ensures that the channel state accurately reflects the updated
|
// This ensures that the channel state accurately reflects the updated
|
||||||
// short channel ID.
|
// short channel ID.
|
||||||
err := l.channel.State().RefreshShortChanID()
|
err := l.channel.State().Refresh()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.log.Errorf("unable to refresh short_chan_id for chan_id=%v: "+
|
l.log.Errorf("unable to refresh short_chan_id for chan_id=%v: "+
|
||||||
"%v", chanID, err)
|
"%v", chanID, err)
|
||||||
|
|
Loading…
Add table
Reference in a new issue