diff --git a/watchtower/blob/type.go b/watchtower/blob/type.go index f77befb89..cef9dfb10 100644 --- a/watchtower/blob/type.go +++ b/watchtower/blob/type.go @@ -26,6 +26,10 @@ const ( // channel, and therefore must expect a P2WSH-style to-remote output if // one exists. FlagAnchorChannel Flag = 1 << 2 + + // FlagTaprootChannel signals that this blob is meant to spend a + // taproot channel and therefore must expect P2TR outputs. + FlagTaprootChannel Flag = 1 << 3 ) // Type returns a Type consisting solely of this flag enabled. @@ -42,6 +46,8 @@ func (f Flag) String() string { return "FlagCommitOutputs" case FlagAnchorChannel: return "FlagAnchorChannel" + case FlagTaprootChannel: + return "FlagTaprootChannel" default: return "FlagUnknown" } @@ -67,6 +73,11 @@ const ( // TypeRewardCommit sweeps only commitment outputs to a sweep address // controlled by the user, and pays a negotiated reward to the tower. TypeRewardCommit = Type(FlagCommitOutputs | FlagReward) + + // TypeAltruistTaprootCommit sweeps only the commitment outputs from a + // taproot channel commitment to a sweep address controlled by the user, + // and does not give the tower a reward. + TypeAltruistTaprootCommit = Type(FlagCommitOutputs | FlagTaprootChannel) ) // Identifier returns a unique, stable string identifier for the blob Type. @@ -78,6 +89,8 @@ func (t Type) Identifier() (string, error) { return "anchor", nil case TypeRewardCommit: return "reward", nil + case TypeAltruistTaprootCommit: + return "taproot", nil default: return "", fmt.Errorf("unknown blob type: %v", t) } @@ -124,14 +137,20 @@ func (t Type) IsAnchorChannel() bool { return t.Has(FlagAnchorChannel) } -// knownFlags maps the supported flags to their name. -var knownFlags = map[Flag]struct{}{ - FlagReward: {}, - FlagCommitOutputs: {}, - FlagAnchorChannel: {}, +// IsTaprootChannel returns true if the blob type is for a taproot channel. +func (t Type) IsTaprootChannel() bool { + return t.Has(FlagTaprootChannel) } -// String returns a human readable description of a Type. +// knownFlags maps the supported flags to their name. +var knownFlags = map[Flag]struct{}{ + FlagReward: {}, + FlagCommitOutputs: {}, + FlagAnchorChannel: {}, + FlagTaprootChannel: {}, +} + +// String returns a human-readable description of a Type. func (t Type) String() string { var ( hrPieces []string @@ -175,9 +194,10 @@ func (t Type) String() string { // supportedTypes is the set of all configurations known to be supported by the // package. var supportedTypes = map[Type]struct{}{ - TypeAltruistCommit: {}, - TypeRewardCommit: {}, - TypeAltruistAnchorCommit: {}, + TypeAltruistCommit: {}, + TypeRewardCommit: {}, + TypeAltruistAnchorCommit: {}, + TypeAltruistTaprootCommit: {}, } // IsSupportedType returns true if the given type is supported by the package. diff --git a/watchtower/blob/type_test.go b/watchtower/blob/type_test.go index 026263df3..87d9a8af1 100644 --- a/watchtower/blob/type_test.go +++ b/watchtower/blob/type_test.go @@ -16,19 +16,28 @@ type typeStringTest struct { var typeStringTests = []typeStringTest{ { - name: "commit no-reward", - typ: blob.TypeAltruistCommit, - expStr: "[No-FlagAnchorChannel|FlagCommitOutputs|No-FlagReward]", + name: "commit no-reward", + typ: blob.TypeAltruistCommit, + expStr: "[No-FlagTaprootChannel|" + + "No-FlagAnchorChannel|" + + "FlagCommitOutputs|" + + "No-FlagReward]", }, { - name: "commit reward", - typ: blob.TypeRewardCommit, - expStr: "[No-FlagAnchorChannel|FlagCommitOutputs|FlagReward]", + name: "commit reward", + typ: blob.TypeRewardCommit, + expStr: "[No-FlagTaprootChannel|" + + "No-FlagAnchorChannel|" + + "FlagCommitOutputs|" + + "FlagReward]", }, { - name: "unknown flag", - typ: unknownFlag.Type(), - expStr: "0000000000010000[No-FlagAnchorChannel|No-FlagCommitOutputs|No-FlagReward]", + name: "unknown flag", + typ: unknownFlag.Type(), + expStr: "0000000000010000[No-FlagTaprootChannel|" + + "No-FlagAnchorChannel|" + + "No-FlagCommitOutputs|" + + "No-FlagReward]", }, } diff --git a/watchtower/wtpolicy/policy.go b/watchtower/wtpolicy/policy.go index 429f1ffb6..c6a2467c6 100644 --- a/watchtower/wtpolicy/policy.go +++ b/watchtower/wtpolicy/policy.go @@ -125,6 +125,12 @@ func (p Policy) IsAnchorChannel() bool { return p.TxPolicy.BlobType.IsAnchorChannel() } +// IsTaprootChannel returns true if the session policy requires taproot +// channels. +func (p Policy) IsTaprootChannel() bool { + return p.TxPolicy.BlobType.IsTaprootChannel() +} + // Validate ensures that the policy satisfies some minimal correctness // constraints. func (p Policy) Validate() error { diff --git a/watchtower/wtpolicy/policy_test.go b/watchtower/wtpolicy/policy_test.go index b73c48456..b3587640d 100644 --- a/watchtower/wtpolicy/policy_test.go +++ b/watchtower/wtpolicy/policy_test.go @@ -93,20 +93,32 @@ func TestPolicyValidate(t *testing.T) { } } -// TestPolicyIsAnchorChannel asserts that the IsAnchorChannel helper properly -// reflects the anchor bit of the policy's blob type. -func TestPolicyIsAnchorChannel(t *testing.T) { - policyNoAnchor := wtpolicy.Policy{ +// TestPolicyIsChannelType asserts that the IsAnchorChannel and IsTaprootChannel +// helpers properly reflect the anchor bit of the policy's blob type. +func TestPolicyIsChannelType(t *testing.T) { + t.Parallel() + + policyLegacy := wtpolicy.Policy{ TxPolicy: wtpolicy.TxPolicy{ BlobType: blob.TypeAltruistCommit, }, } - require.Equal(t, false, policyNoAnchor.IsAnchorChannel()) + require.False(t, policyLegacy.IsAnchorChannel()) + require.False(t, policyLegacy.IsTaprootChannel()) policyAnchor := wtpolicy.Policy{ TxPolicy: wtpolicy.TxPolicy{ BlobType: blob.TypeAltruistAnchorCommit, }, } - require.Equal(t, true, policyAnchor.IsAnchorChannel()) + require.True(t, policyAnchor.IsAnchorChannel()) + require.False(t, policyAnchor.IsTaprootChannel()) + + policyTaproot := wtpolicy.Policy{ + TxPolicy: wtpolicy.TxPolicy{ + BlobType: blob.TypeAltruistTaprootCommit, + }, + } + require.True(t, policyTaproot.IsTaprootChannel()) + require.False(t, policyTaproot.IsAnchorChannel()) } diff --git a/watchtower/wtwire/features.go b/watchtower/wtwire/features.go index 83ab207f7..413e81c1a 100644 --- a/watchtower/wtwire/features.go +++ b/watchtower/wtwire/features.go @@ -9,6 +9,8 @@ var FeatureNames = map[lnwire.FeatureBit]string{ AltruistSessionsOptional: "altruist-sessions", AnchorCommitRequired: "anchor-commit", AnchorCommitOptional: "anchor-commit", + TaprootCommitRequired: "taproot-commit", + TaprootCommitOptional: "taproot-commit", } const ( @@ -30,4 +32,13 @@ const ( // AnchorCommitOptional specifies that the advertising tower allows the // remote party to negotiate sessions for protecting anchor channels. AnchorCommitOptional lnwire.FeatureBit = 3 + + // TaprootCommitRequired specifies that the advertising tower requires + // the remote party to negotiate sessions for protecting taproot + // channels. + TaprootCommitRequired lnwire.FeatureBit = 4 + + // TaprootCommitOptional specifies that the advertising tower allows the + // remote party to negotiate sessions for protecting taproot channels. + TaprootCommitOptional lnwire.FeatureBit = 5 )