watchtower/blob: add taproot Commitment type

This commit is contained in:
Elle Mouton 2023-05-31 08:21:56 +02:00
parent d84a98e3db
commit 5960253357
No known key found for this signature in database
GPG key ID: D7D916376026F177
3 changed files with 263 additions and 57 deletions

View file

@ -27,6 +27,10 @@ const (
// anchor channel. The key differences are that the to_remote is // anchor channel. The key differences are that the to_remote is
// encumbered by a 1 block CSV and so is thus a P2WSH output. // encumbered by a 1 block CSV and so is thus a P2WSH output.
AnchorCommitment AnchorCommitment
// TaprootCommitment represents the commitment transaction of a simple
// taproot channel.
TaprootCommitment
) )
// ToLocalInput constructs the input that will be used to spend the to_local // ToLocalInput constructs the input that will be used to spend the to_local
@ -61,9 +65,10 @@ func (c CommitmentType) ToRemoteInput(info *lnwallet.BreachRetribution) (
info.LocalOutputSignDesc, 0, info.LocalOutputSignDesc, 0,
), nil ), nil
case AnchorCommitment: case AnchorCommitment, TaprootCommitment:
// Anchor channels have a CSV-encumbered to-remote output. We'll // Anchor and Taproot channels have a CSV-encumbered to-remote
// construct a CSV input and assign the proper CSV delay of 1. // output. We'll construct a CSV input and assign the proper CSV
// delay of 1.
return input.NewCsvInput( return input.NewCsvInput(
&info.LocalOutpoint, witnessType, &info.LocalOutpoint, witnessType,
info.LocalOutputSignDesc, 0, 1, info.LocalOutputSignDesc, 0, 1,
@ -80,6 +85,9 @@ func (c CommitmentType) ToLocalWitnessType() (input.WitnessType, error) {
case LegacyTweaklessCommitment, LegacyCommitment, AnchorCommitment: case LegacyTweaklessCommitment, LegacyCommitment, AnchorCommitment:
return input.CommitmentRevoke, nil return input.CommitmentRevoke, nil
case TaprootCommitment:
return input.TaprootCommitmentRevoke, nil
default: default:
return nil, fmt.Errorf("unknown commitment type: %v", c) return nil, fmt.Errorf("unknown commitment type: %v", c)
} }
@ -97,6 +105,9 @@ func (c CommitmentType) ToRemoteWitnessType() (input.WitnessType, error) {
case AnchorCommitment: case AnchorCommitment:
return input.CommitmentToRemoteConfirmed, nil return input.CommitmentToRemoteConfirmed, nil
case TaprootCommitment:
return input.TaprootRemoteCommitSpend, nil
default: default:
return nil, fmt.Errorf("unknown commitment type: %v", c) return nil, fmt.Errorf("unknown commitment type: %v", c)
} }
@ -115,6 +126,10 @@ func (c CommitmentType) ToRemoteWitnessSize() (int, error) {
case AnchorCommitment: case AnchorCommitment:
return input.ToRemoteConfirmedWitnessSize, nil return input.ToRemoteConfirmedWitnessSize, nil
// Taproot channels spend a confirmed P2SH output.
case TaprootCommitment:
return input.TaprootToRemoteWitnessSize, nil
default: default:
return 0, fmt.Errorf("unknown commitment type: %v", c) return 0, fmt.Errorf("unknown commitment type: %v", c)
} }
@ -134,6 +149,9 @@ func (c CommitmentType) ToLocalWitnessSize() (int, error) {
case AnchorCommitment: case AnchorCommitment:
return input.ToLocalPenaltyWitnessSize, nil return input.ToLocalPenaltyWitnessSize, nil
case TaprootCommitment:
return input.TaprootToLocalRevokeWitnessSize, nil
default: default:
return 0, fmt.Errorf("unknown commitment type: %v", c) return 0, fmt.Errorf("unknown commitment type: %v", c)
} }
@ -143,21 +161,22 @@ func (c CommitmentType) ToLocalWitnessSize() (int, error) {
func (c CommitmentType) ParseRawSig(witness wire.TxWitness) (lnwire.Sig, func (c CommitmentType) ParseRawSig(witness wire.TxWitness) (lnwire.Sig,
error) { error) {
// Check that the witness has at least one item since this is required
// for all commitment types to follow.
if len(witness) < 1 {
return lnwire.Sig{}, fmt.Errorf("the witness should have at " +
"least one element")
}
// Check that the first witness element is non-nil. This is to ensure
// that the witness length checks below do not panic.
if witness[0] == nil {
return lnwire.Sig{}, fmt.Errorf("the first witness element " +
"should not be nil")
}
switch c { switch c {
case LegacyCommitment, LegacyTweaklessCommitment, AnchorCommitment: case LegacyCommitment, LegacyTweaklessCommitment, AnchorCommitment:
// Check that the witness has at least one item.
if len(witness) < 1 {
return lnwire.Sig{}, fmt.Errorf("the witness should " +
"have at least one element")
}
// Check that the first witness element is non-nil. This is to
// ensure that the witness length check below does not panic.
if witness[0] == nil {
return lnwire.Sig{}, fmt.Errorf("the first witness " +
"element should not be nil")
}
// Parse the DER-encoded signature from the first position of // Parse the DER-encoded signature from the first position of
// the resulting witness. We trim an extra byte to remove the // the resulting witness. We trim an extra byte to remove the
// sighash flag. // sighash flag.
@ -167,6 +186,16 @@ func (c CommitmentType) ParseRawSig(witness wire.TxWitness) (lnwire.Sig,
// signature. // signature.
return lnwire.NewSigFromECDSARawSignature(rawSignature) return lnwire.NewSigFromECDSARawSignature(rawSignature)
case TaprootCommitment:
rawSignature := witness[0]
if len(rawSignature) > 64 {
rawSignature = witness[0][:len(witness[0])-1]
}
// Re-encode the schnorr signature into a fixed-size 64 byte
// signature.
return lnwire.NewSigFromSchnorrRawSignature(rawSignature)
default: default:
return lnwire.Sig{}, fmt.Errorf("unknown commitment type: %v", return lnwire.Sig{}, fmt.Errorf("unknown commitment type: %v",
c) c)
@ -190,6 +219,11 @@ func (c CommitmentType) NewJusticeKit(sweepScript []byte,
sweepScript, breachInfo, withToRemote, sweepScript, breachInfo, withToRemote,
), nil ), nil
case TaprootCommitment:
return newTaprootJusticeKit(
sweepScript, breachInfo, withToRemote,
)
default: default:
return nil, fmt.Errorf("unknown commitment type: %v", c) return nil, fmt.Errorf("unknown commitment type: %v", c)
} }
@ -207,6 +241,9 @@ func (c CommitmentType) EmptyJusticeKit() (JusticeKit, error) {
legacyJusticeKit: legacyJusticeKit{}, legacyJusticeKit: legacyJusticeKit{},
}, nil }, nil
case TaprootCommitment:
return &taprootJusticeKit{}, nil
default: default:
return nil, fmt.Errorf("unknown commitment type: %v", c) return nil, fmt.Errorf("unknown commitment type: %v", c)
} }

View file

@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/ecdsa" "github.com/btcsuite/btcd/btcec/v2/ecdsa"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
@ -17,6 +18,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const csvDelay = uint32(144)
func makePubKey() *btcec.PublicKey { func makePubKey() *btcec.PublicKey {
priv, _ := btcec.NewPrivateKey() priv, _ := btcec.NewPrivateKey()
return priv.PubKey() return priv.PubKey()
@ -39,6 +42,15 @@ func makeAddr(size int) []byte {
return addr return addr
} }
func makeSchnorrSig(i int) lnwire.Sig {
var sigBytes [64]byte
binary.BigEndian.PutUint64(sigBytes[:8], uint64(i))
sig, _ := lnwire.NewSigFromSchnorrRawSignature(sigBytes[:])
return sig
}
type descriptorTest struct { type descriptorTest struct {
name string name string
encVersion Type encVersion Type
@ -46,7 +58,6 @@ type descriptorTest struct {
sweepAddr []byte sweepAddr []byte
revPubKey *btcec.PublicKey revPubKey *btcec.PublicKey
delayPubKey *btcec.PublicKey delayPubKey *btcec.PublicKey
csvDelay uint32
commitToLocalSig lnwire.Sig commitToLocalSig lnwire.Sig
hasCommitToRemote bool hasCommitToRemote bool
commitToRemotePubKey *btcec.PublicKey commitToRemotePubKey *btcec.PublicKey
@ -63,7 +74,6 @@ var descriptorTests = []descriptorTest{
sweepAddr: makeAddr(22), sweepAddr: makeAddr(22),
revPubKey: makePubKey(), revPubKey: makePubKey(),
delayPubKey: makePubKey(), delayPubKey: makePubKey(),
csvDelay: 144,
commitToLocalSig: makeSig(1), commitToLocalSig: makeSig(1),
}, },
{ {
@ -73,7 +83,6 @@ var descriptorTests = []descriptorTest{
sweepAddr: makeAddr(22), sweepAddr: makeAddr(22),
revPubKey: makePubKey(), revPubKey: makePubKey(),
delayPubKey: makePubKey(), delayPubKey: makePubKey(),
csvDelay: 144,
commitToLocalSig: makeSig(1), commitToLocalSig: makeSig(1),
hasCommitToRemote: true, hasCommitToRemote: true,
commitToRemotePubKey: makePubKey(), commitToRemotePubKey: makePubKey(),
@ -86,7 +95,6 @@ var descriptorTests = []descriptorTest{
sweepAddr: makeAddr(34), sweepAddr: makeAddr(34),
revPubKey: makePubKey(), revPubKey: makePubKey(),
delayPubKey: makePubKey(), delayPubKey: makePubKey(),
csvDelay: 144,
commitToLocalSig: makeSig(1), commitToLocalSig: makeSig(1),
encErr: ErrUnknownBlobType, encErr: ErrUnknownBlobType,
}, },
@ -97,7 +105,6 @@ var descriptorTests = []descriptorTest{
sweepAddr: makeAddr(34), sweepAddr: makeAddr(34),
revPubKey: makePubKey(), revPubKey: makePubKey(),
delayPubKey: makePubKey(), delayPubKey: makePubKey(),
csvDelay: 144,
commitToLocalSig: makeSig(1), commitToLocalSig: makeSig(1),
decErr: ErrUnknownBlobType, decErr: ErrUnknownBlobType,
}, },
@ -108,7 +115,6 @@ var descriptorTests = []descriptorTest{
sweepAddr: makeAddr(0), sweepAddr: makeAddr(0),
revPubKey: makePubKey(), revPubKey: makePubKey(),
delayPubKey: makePubKey(), delayPubKey: makePubKey(),
csvDelay: 144,
commitToLocalSig: makeSig(1), commitToLocalSig: makeSig(1),
}, },
{ {
@ -118,7 +124,6 @@ var descriptorTests = []descriptorTest{
sweepAddr: makeAddr(MaxSweepAddrSize), sweepAddr: makeAddr(MaxSweepAddrSize),
revPubKey: makePubKey(), revPubKey: makePubKey(),
delayPubKey: makePubKey(), delayPubKey: makePubKey(),
csvDelay: 144,
commitToLocalSig: makeSig(1), commitToLocalSig: makeSig(1),
}, },
{ {
@ -128,10 +133,30 @@ var descriptorTests = []descriptorTest{
sweepAddr: makeAddr(MaxSweepAddrSize + 1), sweepAddr: makeAddr(MaxSweepAddrSize + 1),
revPubKey: makePubKey(), revPubKey: makePubKey(),
delayPubKey: makePubKey(), delayPubKey: makePubKey(),
csvDelay: 144,
commitToLocalSig: makeSig(1), commitToLocalSig: makeSig(1),
encErr: ErrSweepAddressToLong, encErr: ErrSweepAddressToLong,
}, },
{
name: "taproot to-local only",
encVersion: TypeAltruistTaprootCommit,
decVersion: TypeAltruistTaprootCommit,
sweepAddr: makeAddr(34),
revPubKey: makePubKey(),
delayPubKey: makePubKey(),
commitToLocalSig: makeSchnorrSig(1),
},
{
name: "taproot to-local and to-remote",
encVersion: TypeAltruistTaprootCommit,
decVersion: TypeAltruistTaprootCommit,
sweepAddr: makeAddr(34),
revPubKey: makePubKey(),
delayPubKey: makePubKey(),
commitToLocalSig: makeSchnorrSig(1),
hasCommitToRemote: true,
commitToRemotePubKey: makePubKey(),
commitToRemoteSig: makeSchnorrSig(2),
},
} }
// TestBlobJusticeKitEncryptDecrypt asserts that encrypting and decrypting a // TestBlobJusticeKitEncryptDecrypt asserts that encrypting and decrypting a
@ -154,7 +179,7 @@ func testBlobJusticeKitEncryptDecrypt(t *testing.T, test descriptorTest) {
} }
breachInfo := &lnwallet.BreachRetribution{ breachInfo := &lnwallet.BreachRetribution{
RemoteDelay: test.csvDelay, RemoteDelay: csvDelay,
KeyRing: &lnwallet.CommitmentKeyRing{ KeyRing: &lnwallet.CommitmentKeyRing{
ToLocalKey: test.delayPubKey, ToLocalKey: test.delayPubKey,
ToRemoteKey: test.commitToRemotePubKey, ToRemoteKey: test.commitToRemotePubKey,
@ -221,6 +246,8 @@ type remoteWitnessTest struct {
name string name string
blobType Type blobType Type
expWitnessScript func(pk *btcec.PublicKey) []byte expWitnessScript func(pk *btcec.PublicKey) []byte
expWitnessStack func(sig input.Signature) wire.TxWitness
createSig func(*btcec.PrivateKey, []byte) input.Signature
} }
// TestJusticeKitRemoteWitnessConstruction tests that a JusticeKit returns the // TestJusticeKitRemoteWitnessConstruction tests that a JusticeKit returns the
@ -234,6 +261,21 @@ func TestJusticeKitRemoteWitnessConstruction(t *testing.T) {
expWitnessScript: func(pk *btcec.PublicKey) []byte { expWitnessScript: func(pk *btcec.PublicKey) []byte {
return pk.SerializeCompressed() return pk.SerializeCompressed()
}, },
expWitnessStack: func(
sig input.Signature) wire.TxWitness {
sigBytes := append(
sig.Serialize(),
byte(txscript.SigHashAll),
)
return [][]byte{sigBytes}
},
createSig: func(priv *btcec.PrivateKey,
digest []byte) input.Signature {
return ecdsa.Sign(priv, digest)
},
}, },
{ {
name: "anchor commitment", name: "anchor commitment",
@ -242,6 +284,42 @@ func TestJusticeKitRemoteWitnessConstruction(t *testing.T) {
script, _ := input.CommitScriptToRemoteConfirmed(pk) script, _ := input.CommitScriptToRemoteConfirmed(pk)
return script return script
}, },
expWitnessStack: func(
sig input.Signature) wire.TxWitness {
sigBytes := append(
sig.Serialize(),
byte(txscript.SigHashAll),
)
return [][]byte{sigBytes}
},
createSig: func(priv *btcec.PrivateKey,
digest []byte) input.Signature {
return ecdsa.Sign(priv, digest)
},
},
{
name: "taproot commitment",
blobType: TypeAltruistTaprootCommit,
expWitnessScript: func(pk *btcec.PublicKey) []byte {
tree, _ := input.NewRemoteCommitScriptTree(pk)
return tree.SettleLeaf.Script
},
expWitnessStack: func(
sig input.Signature) wire.TxWitness {
return [][]byte{sig.Serialize()}
},
createSig: func(priv *btcec.PrivateKey,
digest []byte) input.Signature {
sig, _ := schnorr.Sign(priv, digest)
return sig
},
}, },
} }
for _, test := range tests { for _, test := range tests {
@ -252,8 +330,8 @@ func TestJusticeKitRemoteWitnessConstruction(t *testing.T) {
} }
} }
func testJusticeKitRemoteWitnessConstruction( func testJusticeKitRemoteWitnessConstruction(t *testing.T,
t *testing.T, test remoteWitnessTest) { test remoteWitnessTest) {
// Generate the to-remote pubkey. // Generate the to-remote pubkey.
toRemotePrivKey, err := btcec.NewPrivateKey() toRemotePrivKey, err := btcec.NewPrivateKey()
@ -268,7 +346,7 @@ func testJusticeKitRemoteWitnessConstruction(
// Sign a message using the to-remote private key. The exact message // Sign a message using the to-remote private key. The exact message
// doesn't matter as we won't be validating the signature's validity. // doesn't matter as we won't be validating the signature's validity.
digest := bytes.Repeat([]byte("a"), 32) digest := bytes.Repeat([]byte("a"), 32)
rawToRemoteSig := ecdsa.Sign(toRemotePrivKey, digest) rawToRemoteSig := test.createSig(toRemotePrivKey, digest)
// Convert the DER-encoded signature into a fixed-size sig. // Convert the DER-encoded signature into a fixed-size sig.
commitToRemoteSig, err := lnwire.NewSigFromSignature(rawToRemoteSig) commitToRemoteSig, err := lnwire.NewSigFromSignature(rawToRemoteSig)
@ -298,24 +376,122 @@ func testJusticeKitRemoteWitnessConstruction(
expToRemoteScript := test.expWitnessScript(toRemotePrivKey.PubKey()) expToRemoteScript := test.expWitnessScript(toRemotePrivKey.PubKey())
require.Equal(t, expToRemoteScript, witness[1]) require.Equal(t, expToRemoteScript, witness[1])
// Compute the expected first element, by appending a sighash all byte // Compute the expected signature.
// to our raw DER-encoded signature. expWitnessStack := test.expWitnessStack(rawToRemoteSig)
rawToRemoteSigWithSigHash := append(
rawToRemoteSig.Serialize(), byte(txscript.SigHashAll),
)
// Assert that the expected witness stack is returned.
expWitnessStack := wire.TxWitness{
rawToRemoteSigWithSigHash,
}
require.Equal(t, expWitnessStack, witness[:1]) require.Equal(t, expWitnessStack, witness[:1])
} }
type localWitnessTest struct {
name string
blobType Type
expWitnessScript func(delay, rev *btcec.PublicKey) []byte
expWitnessStack func(sig input.Signature) wire.TxWitness
witnessScriptIndex int
createSig func(*btcec.PrivateKey, []byte) input.Signature
}
// TestJusticeKitToLocalWitnessConstruction tests that a JusticeKit returns the // TestJusticeKitToLocalWitnessConstruction tests that a JusticeKit returns the
// proper to-local witness script and to-local witness stack for spending the // proper to-local witness script and to-local witness stack for spending the
// revocation path. // revocation path.
func TestJusticeKitToLocalWitnessConstruction(t *testing.T) { func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
csvDelay := uint32(144) tests := []localWitnessTest{
{
name: "legacy commitment",
blobType: TypeAltruistCommit,
expWitnessScript: func(delay,
rev *btcec.PublicKey) []byte {
script, _ := input.CommitScriptToSelf(
csvDelay, delay, rev,
)
return script
},
expWitnessStack: func(
sig input.Signature) wire.TxWitness {
sigBytes := append(
sig.Serialize(),
byte(txscript.SigHashAll),
)
return [][]byte{sigBytes, {1}}
},
witnessScriptIndex: 2,
createSig: func(priv *btcec.PrivateKey,
digest []byte) input.Signature {
return ecdsa.Sign(priv, digest)
},
},
{
name: "anchor commitment",
blobType: TypeAltruistAnchorCommit,
expWitnessScript: func(delay,
rev *btcec.PublicKey) []byte {
script, _ := input.CommitScriptToSelf(
csvDelay, delay, rev,
)
return script
},
witnessScriptIndex: 2,
expWitnessStack: func(
sig input.Signature) wire.TxWitness {
sigBytes := append(
sig.Serialize(),
byte(txscript.SigHashAll),
)
return [][]byte{sigBytes, {1}}
},
createSig: func(priv *btcec.PrivateKey,
digest []byte) input.Signature {
return ecdsa.Sign(priv, digest)
},
},
{
name: "taproot commitment",
blobType: TypeAltruistTaprootCommit,
expWitnessScript: func(delay,
rev *btcec.PublicKey) []byte {
script, _ := input.NewLocalCommitScriptTree(
csvDelay, delay, rev,
)
return script.RevocationLeaf.Script
},
witnessScriptIndex: 1,
expWitnessStack: func(
sig input.Signature) wire.TxWitness {
return [][]byte{sig.Serialize()}
},
createSig: func(priv *btcec.PrivateKey,
digest []byte) input.Signature {
sig, _ := schnorr.Sign(priv, digest)
return sig
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
testJusticeKitToLocalWitnessConstruction(t, test)
})
}
}
func testJusticeKitToLocalWitnessConstruction(t *testing.T,
test localWitnessTest) {
// Generate the revocation and delay private keys. // Generate the revocation and delay private keys.
revPrivKey, err := btcec.NewPrivateKey() revPrivKey, err := btcec.NewPrivateKey()
@ -327,13 +503,13 @@ func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
// Sign a message using the revocation private key. The exact message // Sign a message using the revocation private key. The exact message
// doesn't matter as we won't be validating the signature's validity. // doesn't matter as we won't be validating the signature's validity.
digest := bytes.Repeat([]byte("a"), 32) digest := bytes.Repeat([]byte("a"), 32)
rawRevSig := ecdsa.Sign(revPrivKey, digest) rawRevSig := test.createSig(revPrivKey, digest)
// Convert the DER-encoded signature into a fixed-size sig. // Convert the DER-encoded signature into a fixed-size sig.
commitToLocalSig, err := lnwire.NewSigFromSignature(rawRevSig) commitToLocalSig, err := lnwire.NewSigFromSignature(rawRevSig)
require.NoError(t, err) require.NoError(t, err)
commitType, err := TypeAltruistCommit.CommitmentType(nil) commitType, err := test.blobType.CommitmentType(nil)
require.NoError(t, err) require.NoError(t, err)
breachInfo := &lnwallet.BreachRetribution{ breachInfo := &lnwallet.BreachRetribution{
@ -350,28 +526,18 @@ func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
// Compute the expected to-local script, which is a function of the CSV // Compute the expected to-local script, which is a function of the CSV
// delay, revocation pubkey and delay pubkey. // delay, revocation pubkey and delay pubkey.
expToLocalScript, err := input.CommitScriptToSelf( expToLocalScript := test.expWitnessScript(
csvDelay, delayPrivKey.PubKey(), revPrivKey.PubKey(), delayPrivKey.PubKey(), revPrivKey.PubKey(),
) )
require.NoError(t, err)
// Compute the to-local script that is returned by the justice kit. // Compute the to-local script that is returned by the justice kit.
_, witness, err := justiceKit.ToLocalOutputSpendInfo() _, witness, err := justiceKit.ToLocalOutputSpendInfo()
require.NoError(t, err) require.NoError(t, err)
// Assert that the expected to-local script matches the actual script. // Assert that the expected to-local script matches the actual script.
require.Equal(t, expToLocalScript, witness[2]) require.Equal(t, expToLocalScript, witness[test.witnessScriptIndex])
// Compute the expected signature in the bottom element of the stack, by // Finally, validate the witness.
// appending a sighash all flag to the raw DER signature. expWitnessStack := test.expWitnessStack(rawRevSig)
rawRevSigWithSigHash := append( require.Equal(t, expWitnessStack, witness[:test.witnessScriptIndex])
rawRevSig.Serialize(), byte(txscript.SigHashAll),
)
// Finally, validate against our expected witness stack.
expWitnessStack := wire.TxWitness{
rawRevSigWithSigHash,
{1},
}
require.Equal(t, expWitnessStack, witness[:2])
} }

View file

@ -102,6 +102,9 @@ func (t Type) CommitmentType(chanType *channeldb.ChannelType) (CommitmentType,
error) { error) {
switch { switch {
case t.Has(FlagTaprootChannel):
return TaprootCommitment, nil
case t.Has(FlagAnchorChannel): case t.Has(FlagAnchorChannel):
return AnchorCommitment, nil return AnchorCommitment, nil