mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-09 06:29:55 +02:00
contractcourt: register spend notification during init
This commit moves the creation of the spending notification from `Start` to `newChainWatcher` so we subscribe the spending event before handling the block, which is needed to properly handle the blockbeat.
This commit is contained in:
parent
07cb3aef00
commit
c1a9390c36
@ -241,6 +241,10 @@ type chainWatcher struct {
|
|||||||
// clientSubscriptions is a map that keeps track of all the active
|
// clientSubscriptions is a map that keeps track of all the active
|
||||||
// client subscriptions for events related to this channel.
|
// client subscriptions for events related to this channel.
|
||||||
clientSubscriptions map[uint64]*ChainEventSubscription
|
clientSubscriptions map[uint64]*ChainEventSubscription
|
||||||
|
|
||||||
|
// fundingSpendNtfn is the spending notification subscription for the
|
||||||
|
// funding outpoint.
|
||||||
|
fundingSpendNtfn *chainntnfs.SpendEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
// newChainWatcher returns a new instance of a chainWatcher for a channel given
|
// newChainWatcher returns a new instance of a chainWatcher for a channel given
|
||||||
@ -265,11 +269,32 @@ func newChainWatcher(cfg chainWatcherConfig) (*chainWatcher, error) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the witness script for the funding output.
|
||||||
|
fundingPkScript, err := deriveFundingPkScript(chanState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the channel opening block height.
|
||||||
|
heightHint := deriveHeightHint(chanState)
|
||||||
|
|
||||||
|
// We'll register for a notification to be dispatched if the funding
|
||||||
|
// output is spent.
|
||||||
|
spendNtfn, err := cfg.notifier.RegisterSpendNtfn(
|
||||||
|
&chanState.FundingOutpoint, fundingPkScript, heightHint,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
c := &chainWatcher{
|
c := &chainWatcher{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
stateHintObfuscator: stateHint,
|
stateHintObfuscator: stateHint,
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
clientSubscriptions: make(map[uint64]*ChainEventSubscription),
|
clientSubscriptions: make(map[uint64]*ChainEventSubscription),
|
||||||
|
fundingPkScript: fundingPkScript,
|
||||||
|
heightHint: heightHint,
|
||||||
|
fundingSpendNtfn: spendNtfn,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount the block consumer.
|
// Mount the block consumer.
|
||||||
@ -295,75 +320,11 @@ func (c *chainWatcher) Start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
chanState := c.cfg.chanState
|
|
||||||
log.Debugf("Starting chain watcher for ChannelPoint(%v)",
|
log.Debugf("Starting chain watcher for ChannelPoint(%v)",
|
||||||
chanState.FundingOutpoint)
|
c.cfg.chanState.FundingOutpoint)
|
||||||
|
|
||||||
// First, we'll register for a notification to be dispatched if the
|
|
||||||
// funding output is spent.
|
|
||||||
fundingOut := &chanState.FundingOutpoint
|
|
||||||
|
|
||||||
// As a height hint, we'll try to use the opening height, but if the
|
|
||||||
// channel isn't yet open, then we'll use the height it was broadcast
|
|
||||||
// at. This may be an unconfirmed zero-conf channel.
|
|
||||||
c.heightHint = c.cfg.chanState.ShortChanID().BlockHeight
|
|
||||||
if c.heightHint == 0 {
|
|
||||||
c.heightHint = chanState.BroadcastHeight()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since no zero-conf state is stored in a channel backup, the below
|
|
||||||
// logic will not be triggered for restored, zero-conf channels. Set
|
|
||||||
// the height hint for zero-conf channels.
|
|
||||||
if chanState.IsZeroConf() {
|
|
||||||
if chanState.ZeroConfConfirmed() {
|
|
||||||
// If the zero-conf channel is confirmed, we'll use the
|
|
||||||
// confirmed SCID's block height.
|
|
||||||
c.heightHint = chanState.ZeroConfRealScid().BlockHeight
|
|
||||||
} else {
|
|
||||||
// The zero-conf channel is unconfirmed. We'll need to
|
|
||||||
// use the FundingBroadcastHeight.
|
|
||||||
c.heightHint = chanState.BroadcastHeight()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
localKey := chanState.LocalChanCfg.MultiSigKey.PubKey
|
|
||||||
remoteKey := chanState.RemoteChanCfg.MultiSigKey.PubKey
|
|
||||||
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if chanState.ChanType.IsTaproot() {
|
|
||||||
c.fundingPkScript, _, err = input.GenTaprootFundingScript(
|
|
||||||
localKey, remoteKey, 0, chanState.TapscriptRoot,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
multiSigScript, err := input.GenMultiSigScript(
|
|
||||||
localKey.SerializeCompressed(),
|
|
||||||
remoteKey.SerializeCompressed(),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.fundingPkScript, err = input.WitnessScriptHash(multiSigScript)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spendNtfn, err := c.cfg.notifier.RegisterSpendNtfn(
|
|
||||||
fundingOut, c.fundingPkScript, c.heightHint,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// With the spend notification obtained, we'll now dispatch the
|
|
||||||
// closeObserver which will properly react to any changes.
|
|
||||||
c.wg.Add(1)
|
c.wg.Add(1)
|
||||||
go c.closeObserver(spendNtfn)
|
go c.closeObserver()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -642,8 +603,9 @@ func newChainSet(chanState *channeldb.OpenChannel) (*chainSet, error) {
|
|||||||
// close observer will assembled the proper materials required to claim the
|
// close observer will assembled the proper materials required to claim the
|
||||||
// funds of the channel on-chain (if required), then dispatch these as
|
// funds of the channel on-chain (if required), then dispatch these as
|
||||||
// notifications to all subscribers.
|
// notifications to all subscribers.
|
||||||
func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
|
func (c *chainWatcher) closeObserver() {
|
||||||
defer c.wg.Done()
|
defer c.wg.Done()
|
||||||
|
defer c.fundingSpendNtfn.Cancel()
|
||||||
|
|
||||||
log.Infof("Close observer for ChannelPoint(%v) active",
|
log.Infof("Close observer for ChannelPoint(%v) active",
|
||||||
c.cfg.chanState.FundingOutpoint)
|
c.cfg.chanState.FundingOutpoint)
|
||||||
@ -683,7 +645,7 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
|
|||||||
// TODO(Roasbeef): need to be able to ensure this only triggers
|
// TODO(Roasbeef): need to be able to ensure this only triggers
|
||||||
// on confirmation, to ensure if multiple txns are broadcast, we
|
// on confirmation, to ensure if multiple txns are broadcast, we
|
||||||
// act on the one that's timestamped
|
// act on the one that's timestamped
|
||||||
case commitSpend, ok := <-spendNtfn.Spend:
|
case commitSpend, ok := <-c.fundingSpendNtfn.Spend:
|
||||||
// If the channel was closed, then this means that the notifier
|
// If the channel was closed, then this means that the notifier
|
||||||
// exited, so we will as well.
|
// exited, so we will as well.
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1432,3 +1394,65 @@ func (c *chainWatcher) waitForCommitmentPoint() *btcec.PublicKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deriveFundingPkScript derives the script used in the funding output.
|
||||||
|
func deriveFundingPkScript(chanState *channeldb.OpenChannel) ([]byte, error) {
|
||||||
|
localKey := chanState.LocalChanCfg.MultiSigKey.PubKey
|
||||||
|
remoteKey := chanState.RemoteChanCfg.MultiSigKey.PubKey
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
fundingPkScript []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
if chanState.ChanType.IsTaproot() {
|
||||||
|
fundingPkScript, _, err = input.GenTaprootFundingScript(
|
||||||
|
localKey, remoteKey, 0, chanState.TapscriptRoot,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
multiSigScript, err := input.GenMultiSigScript(
|
||||||
|
localKey.SerializeCompressed(),
|
||||||
|
remoteKey.SerializeCompressed(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fundingPkScript, err = input.WitnessScriptHash(multiSigScript)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fundingPkScript, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// deriveHeightHint derives the block height for the channel opening.
|
||||||
|
func deriveHeightHint(chanState *channeldb.OpenChannel) uint32 {
|
||||||
|
// As a height hint, we'll try to use the opening height, but if the
|
||||||
|
// channel isn't yet open, then we'll use the height it was broadcast
|
||||||
|
// at. This may be an unconfirmed zero-conf channel.
|
||||||
|
heightHint := chanState.ShortChanID().BlockHeight
|
||||||
|
if heightHint == 0 {
|
||||||
|
heightHint = chanState.BroadcastHeight()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since no zero-conf state is stored in a channel backup, the below
|
||||||
|
// logic will not be triggered for restored, zero-conf channels. Set
|
||||||
|
// the height hint for zero-conf channels.
|
||||||
|
if chanState.IsZeroConf() {
|
||||||
|
if chanState.ZeroConfConfirmed() {
|
||||||
|
// If the zero-conf channel is confirmed, we'll use the
|
||||||
|
// confirmed SCID's block height.
|
||||||
|
heightHint = chanState.ZeroConfRealScid().BlockHeight
|
||||||
|
} else {
|
||||||
|
// The zero-conf channel is unconfirmed. We'll need to
|
||||||
|
// use the FundingBroadcastHeight.
|
||||||
|
heightHint = chanState.BroadcastHeight()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return heightHint
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user