Skip to content

Commit

Permalink
contractcourt: for taproot channels, wait for conf in closeObserver
Browse files Browse the repository at this point in the history
This ensures that we end up playing the target output on chain for
taproot channels.
  • Loading branch information
Roasbeef committed Jul 26, 2023
1 parent a5a0474 commit 8cfdf30
Showing 1 changed file with 43 additions and 10 deletions.
53 changes: 43 additions & 10 deletions contractcourt/chain_watcher.go
Expand Up @@ -207,6 +207,13 @@ type chainWatcher struct {
// the current state number on the commitment transactions.
stateHintObfuscator [lnwallet.StateHintSize]byte

// fundingPkScript is the pkScript of the funding output.
fundingPkScript []byte

// heightHint is the height hint used to checkpoint scans on chain for
// conf/spend events.
heightHint uint32

// All the fields below are protected by this mutex.
sync.Mutex

Expand Down Expand Up @@ -267,9 +274,9 @@ func (c *chainWatcher) Start() error {
// 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 := c.cfg.chanState.ShortChanID().BlockHeight
if heightHint == 0 {
heightHint = chanState.BroadcastHeight()
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
Expand All @@ -279,23 +286,22 @@ func (c *chainWatcher) Start() error {
if chanState.ZeroConfConfirmed() {
// If the zero-conf channel is confirmed, we'll use the
// confirmed SCID's block height.
heightHint = chanState.ZeroConfRealScid().BlockHeight
c.heightHint = chanState.ZeroConfRealScid().BlockHeight
} else {
// The zero-conf channel is unconfirmed. We'll need to
// use the FundingBroadcastHeight.
heightHint = chanState.BroadcastHeight()
c.heightHint = chanState.BroadcastHeight()
}
}

localKey := chanState.LocalChanCfg.MultiSigKey.PubKey
remoteKey := chanState.RemoteChanCfg.MultiSigKey.PubKey

var (
pkScript []byte
err error
err error
)
if chanState.ChanType.IsTaproot() {
pkScript, _, err = input.GenTaprootFundingScript(
c.fundingPkScript, _, err = input.GenTaprootFundingScript(
localKey, remoteKey, 0,
)
if err != nil {
Expand All @@ -309,14 +315,14 @@ func (c *chainWatcher) Start() error {
if err != nil {
return err
}
pkScript, err = input.WitnessScriptHash(multiSigScript)
c.fundingPkScript, err = input.WitnessScriptHash(multiSigScript)
if err != nil {
return err
}
}

spendNtfn, err := c.cfg.notifier.RegisterSpendNtfn(
fundingOut, pkScript, heightHint,
fundingOut, c.fundingPkScript, c.heightHint,
)
if err != nil {
return err
Expand Down Expand Up @@ -582,6 +588,33 @@ func (c *chainWatcher) closeObserver(spendNtfn *chainntnfs.SpendEvent) {
log.Infof("Close observer for ChannelPoint(%v) active",
c.cfg.chanState.FundingOutpoint)

// If this is a taproot channel, before we proceed, we want to ensure
// that the expected funding output has confirmed on chain.
if c.cfg.chanState.ChanType.IsTaproot() {
fundingPoint := c.cfg.chanState.FundingOutpoint

confNtfn, err := c.cfg.notifier.RegisterConfirmationsNtfn(
&fundingPoint.Hash, c.fundingPkScript, 1, c.heightHint,
)
if err != nil {
log.Warnf("unable to register for conf: %v", err)
}

log.Infof("Waiting for taproot ChannelPoint(%v) to confirm...",
c.cfg.chanState.FundingOutpoint)

select {
case _, ok := <-confNtfn.Confirmed:
// If the channel was closed, then this means that the
// notifier exited, so we will as well.
if !ok {
return
}
case <-c.quit:
return
}
}

select {
// We've detected a spend of the channel onchain! Depending on the type
// of spend, we'll act accordingly, so we'll examine the spending
Expand Down

0 comments on commit 8cfdf30

Please sign in to comment.