contractcourt: update UTXO nursery to support taproot chans

This commit is contained in:
Olaoluwa Osuntokun committed 2023-08-22 16:33:42 -07:00
1 parent cdcde6e0a5
commit 7e2d04a310
2 files changed
+94 -13

No files matched your search

+94 -11
View File
@@ -10,6 +10,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
@@ -368,10 +369,23 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
// second-layer HTLC output. We effectively skip the baby stage (as the // second-layer HTLC output. We effectively skip the baby stage (as the
// timelock is zero), and enter the kid stage. // timelock is zero), and enter the kid stage.
for _, htlcRes := range incomingHtlcs { for _, htlcRes := range incomingHtlcs {
// Based on the input pk script of the sign descriptor, we can
// determine if this is a taproot output or not. This'll
// determine the witness type we try to set below.
isTaproot := txscript.IsPayToTaproot(
htlcRes.SweepSignDesc.Output.PkScript,
)
var witType input.StandardWitnessType
if isTaproot {
witType = input.TaprootHtlcAcceptedSuccessSecondLevel
} else {
witType = input.HtlcAcceptedSuccessSecondLevel
}
htlcOutput := makeKidOutput( htlcOutput := makeKidOutput(
&htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay, &htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay,
input.HtlcAcceptedSuccessSecondLevel, witType, &htlcRes.SweepSignDesc, 0,
&htlcRes.SweepSignDesc, 0,
) )
if htlcOutput.Amount() > 0 { if htlcOutput.Amount() > 0 {
@@ -396,6 +410,20 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
continue continue
} }
// Based on the input pk script of the sign descriptor, we can
// determine if this is a taproot output or not. This'll
// determine the witness type we try to set below.
isTaproot := txscript.IsPayToTaproot(
htlcRes.SweepSignDesc.Output.PkScript,
)
var witType input.StandardWitnessType
if isTaproot {
witType = input.TaprootHtlcOfferedRemoteTimeout
} else {
witType = input.HtlcOfferedRemoteTimeout
}
// Otherwise, this is actually a kid output as we can sweep it // Otherwise, this is actually a kid output as we can sweep it
// once the commitment transaction confirms, and the absolute // once the commitment transaction confirms, and the absolute
// CLTV lock has expired. We set the CSV delay what the // CLTV lock has expired. We set the CSV delay what the
@@ -403,8 +431,7 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
// accordingly. // accordingly.
htlcOutput := makeKidOutput( htlcOutput := makeKidOutput(
&htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay, &htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay,
input.HtlcOfferedRemoteTimeout, witType, &htlcRes.SweepSignDesc, htlcRes.Expiry,
&htlcRes.SweepSignDesc, htlcRes.Expiry,
) )
kidOutputs = append(kidOutputs, htlcOutput) kidOutputs = append(kidOutputs, htlcOutput)
} }
@@ -516,13 +543,15 @@ func (u *UtxoNursery) NurseryReport(
// confirmation of the commitment transaction. // confirmation of the commitment transaction.
switch kid.WitnessType() { switch kid.WitnessType() {
case input.HtlcAcceptedSuccessSecondLevel: case input.HtlcAcceptedSuccessSecondLevel,
input.TaprootHtlcAcceptedSuccessSecondLevel:
// An HTLC output on our commitment transaction // An HTLC output on our commitment transaction
// where the second-layer transaction hasn't // where the second-layer transaction hasn't
// yet confirmed. // yet confirmed.
report.AddLimboStage1SuccessHtlc(&kid) report.AddLimboStage1SuccessHtlc(&kid)
case input.HtlcOfferedRemoteTimeout: case input.HtlcOfferedRemoteTimeout,
input.TaprootHtlcOfferedRemoteTimeout:
// This is an HTLC output on the // This is an HTLC output on the
// commitment transaction of the remote // commitment transaction of the remote
// party. We are waiting for the CLTV // party. We are waiting for the CLTV
@@ -537,7 +566,8 @@ func (u *UtxoNursery) NurseryReport(
// types. // types.
switch kid.WitnessType() { switch kid.WitnessType() {
case input.HtlcOfferedRemoteTimeout: case input.HtlcOfferedRemoteTimeout,
input.TaprootHtlcOfferedRemoteTimeout:
// This is an HTLC output on the // This is an HTLC output on the
// commitment transaction of the remote // commitment transaction of the remote
// party. The CLTV timelock has // party. The CLTV timelock has
@@ -545,6 +575,10 @@ func (u *UtxoNursery) NurseryReport(
// it. // it.
report.AddLimboDirectHtlc(&kid) report.AddLimboDirectHtlc(&kid)
case input.TaprootHtlcAcceptedSuccessSecondLevel:
fallthrough
case input.TaprootHtlcOfferedTimeoutSecondLevel:
fallthrough
case input.HtlcAcceptedSuccessSecondLevel: case input.HtlcAcceptedSuccessSecondLevel:
fallthrough fallthrough
case input.HtlcOfferedTimeoutSecondLevel: case input.HtlcOfferedTimeoutSecondLevel:
@@ -561,10 +595,16 @@ func (u *UtxoNursery) NurseryReport(
// balance. // balance.
switch kid.WitnessType() { switch kid.WitnessType() {
case input.TaprootHtlcAcceptedSuccessSecondLevel:
fallthrough
case input.TaprootHtlcOfferedTimeoutSecondLevel:
fallthrough
case input.HtlcAcceptedSuccessSecondLevel: case input.HtlcAcceptedSuccessSecondLevel:
fallthrough fallthrough
case input.HtlcOfferedTimeoutSecondLevel: case input.HtlcOfferedTimeoutSecondLevel:
fallthrough fallthrough
case input.TaprootHtlcOfferedRemoteTimeout:
fallthrough
case input.HtlcOfferedRemoteTimeout: case input.HtlcOfferedRemoteTimeout:
// This htlc output successfully // This htlc output successfully
// resides in a p2wkh output belonging // resides in a p2wkh output belonging
@@ -731,7 +771,8 @@ func (u *UtxoNursery) graduateClass(classHeight uint32) error {
// Fetch all information about the crib and kindergarten outputs at // Fetch all information about the crib and kindergarten outputs at
// this height. // this height.
kgtnOutputs, cribOutputs, err := u.cfg.Store.FetchClass( kgtnOutputs, cribOutputs, err := u.cfg.Store.FetchClass(
classHeight) classHeight,
)
if err != nil { if err != nil {
return err return err
} }
@@ -1225,7 +1266,17 @@ func makeBabyOutput(chanPoint *wire.OutPoint,
htlcOutpoint := htlcResolution.ClaimOutpoint htlcOutpoint := htlcResolution.ClaimOutpoint
blocksToMaturity := htlcResolution.CsvDelay blocksToMaturity := htlcResolution.CsvDelay
witnessType := input.HtlcOfferedTimeoutSecondLevel
isTaproot := txscript.IsPayToTaproot(
htlcResolution.SweepSignDesc.Output.PkScript,
)
var witnessType input.StandardWitnessType
if isTaproot {
witnessType = input.TaprootHtlcOfferedTimeoutSecondLevel
} else {
witnessType = input.HtlcOfferedTimeoutSecondLevel
}
kid := makeKidOutput( kid := makeKidOutput(
&htlcOutpoint, chanPoint, blocksToMaturity, witnessType, &htlcOutpoint, chanPoint, blocksToMaturity, witnessType,
@@ -1313,6 +1364,8 @@ func makeKidOutput(outpoint, originChanPoint *wire.OutPoint,
// transaction, or is an outgoing HTLC on the commitment transaction of // transaction, or is an outgoing HTLC on the commitment transaction of
// the remote peer. // the remote peer.
isHtlc := (witnessType == input.HtlcAcceptedSuccessSecondLevel || isHtlc := (witnessType == input.HtlcAcceptedSuccessSecondLevel ||
witnessType == input.TaprootHtlcAcceptedSuccessSecondLevel ||
witnessType == input.TaprootHtlcOfferedRemoteTimeout ||
witnessType == input.HtlcOfferedRemoteTimeout) witnessType == input.HtlcOfferedRemoteTimeout)
// heightHint can be safely set to zero here, because after this // heightHint can be safely set to zero here, because after this
@@ -1389,7 +1442,17 @@ func (k *kidOutput) Encode(w io.Writer) error {
return err return err
} }
return input.WriteSignDescriptor(w, k.SignDesc()) if err := input.WriteSignDescriptor(w, k.SignDesc()); err != nil {
return err
}
if k.SignDesc().ControlBlock == nil {
return nil
}
// If this is a taproot output, then it'll also have a control block,
// so we'll go ahead and write that now.
return wire.WriteVarBytes(w, 1000, k.SignDesc().ControlBlock)
} }
// Decode takes a byte array representation of a kidOutput and converts it to an // Decode takes a byte array representation of a kidOutput and converts it to an
@@ -1436,7 +1499,27 @@ func (k *kidOutput) Decode(r io.Reader) error {
} }
k.witnessType = input.StandardWitnessType(byteOrder.Uint16(scratch[:2])) k.witnessType = input.StandardWitnessType(byteOrder.Uint16(scratch[:2]))
return input.ReadSignDescriptor(r, &k.signDesc) if err := input.ReadSignDescriptor(r, &k.signDesc); err != nil {
return err
}
// If there's anything left in the reader, then this is a taproot
// output that also wrote a control block.
ctrlBlock, err := wire.ReadVarBytes(r, 0, 1000, "control block")
switch {
// If there're no bytes remaining, then we'll return early.
case errors.Is(err, io.EOF):
fallthrough
case errors.Is(err, io.ErrUnexpectedEOF):
return nil
case err != nil:
return err
}
k.signDesc.ControlBlock = ctrlBlock
return nil
} }
// TODO(bvu): copied from channeldb, remove repetition // TODO(bvu): copied from channeldb, remove repetition
-2
View File
@@ -225,8 +225,6 @@ func WriteSignDescriptor(w io.Writer, sd *SignDescriptor) error {
return err return err
} }
// TODO(roasbeef): also write ctrl block?
return nil return nil
} }