Skip to content

Commit

Permalink
watchtower/wtclient: prep client for taproot towers
Browse files Browse the repository at this point in the history
  • Loading branch information
ellemouton committed May 31, 2023
1 parent 80dff06 commit ddc029c
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 36 deletions.
13 changes: 13 additions & 0 deletions watchtower/blob/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ const (
TypeAltruistTaprootCommit = Type(FlagCommitOutputs | FlagTaprootChannel)
)

// TypeFromChannel returns the appropriate blob Type for the given channel
// type.
func TypeFromChannel(chanType channeldb.ChannelType) Type {
switch {
case chanType.IsTaproot():
return TypeAltruistTaprootCommit
case chanType.HasAnchors():
return TypeAltruistAnchorCommit
default:
return TypeAltruistCommit
}
}

// Identifier returns a unique, stable string identifier for the blob Type.
func (t Type) Identifier() (string, error) {
switch t {
Expand Down
134 changes: 114 additions & 20 deletions watchtower/wtclient/backup_task_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,12 @@ func genTaskTest(
bindErr error,
chanType channeldb.ChannelType) backupTaskTest {

// Set the anchor flag in the blob type if the session needs to support
// anchor channels.
// Set the anchor or taproot flag in the blob type if the session needs
// to support anchor or taproot channels.
if chanType.HasAnchors() {
blobType |= blob.Type(blob.FlagAnchorChannel)
} else if chanType.IsTaproot() {
blobType |= blob.Type(blob.FlagTaprootChannel)
}

// Parse the key pairs for all keys used in the test.
Expand Down Expand Up @@ -129,30 +131,112 @@ func genTaskTest(
// to that output as local, though relative to their commitment, it is
// paying to-the-remote party (which is us).
if toLocalAmt > 0 {
toLocalSignDesc := &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: revKeyLoc,
PubKey: revPK,
},
Output: &wire.TxOut{
Value: toLocalAmt,
},
HashType: txscript.SigHashAll,
var toLocalSignDesc *input.SignDescriptor

if chanType.IsTaproot() {
scriptTree, _ := input.NewLocalCommitScriptTree(
csvDelay, toLocalPK, revPK,
)

pkScript, _ := input.PayToTaprootScript(
scriptTree.TaprootKey,
)

revokeTapleafHash := txscript.NewBaseTapLeaf(
scriptTree.RevocationLeaf.Script,
).TapHash()

tapTree := scriptTree.TapscriptTree
revokeIdx := tapTree.LeafProofIndex[revokeTapleafHash]
revokeMerkleProof := tapTree.LeafMerkleProofs[revokeIdx]
revokeControlBlock := revokeMerkleProof.ToControlBlock(
&input.TaprootNUMSKey,
)
ctrlBytes, _ := revokeControlBlock.ToBytes()

toLocalSignDesc = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: revKeyLoc,
PubKey: revPK,
},
Output: &wire.TxOut{
Value: toLocalAmt,
PkScript: pkScript,
},
WitnessScript: scriptTree.RevocationLeaf.Script,
SignMethod: input.TaprootScriptSpendSignMethod, //nolint:lll
HashType: txscript.SigHashDefault,
ControlBlock: ctrlBytes,
}
} else {
toLocalSignDesc = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: revKeyLoc,
PubKey: revPK,
},
Output: &wire.TxOut{
Value: toLocalAmt,
},
HashType: txscript.SigHashAll,
}
}

breachInfo.RemoteOutputSignDesc = toLocalSignDesc
breachTxn.AddTxOut(toLocalSignDesc.Output)
}
if toRemoteAmt > 0 {
toRemoteSignDesc := &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: toRemoteKeyLoc,
PubKey: toRemotePK,
},
Output: &wire.TxOut{
Value: toRemoteAmt,
},
HashType: txscript.SigHashAll,
var toRemoteSignDesc *input.SignDescriptor

if chanType.IsTaproot() {
scriptTree, _ := input.NewRemoteCommitScriptTree(
toRemotePK,
)

pkScript, _ := input.PayToTaprootScript(
scriptTree.TaprootKey,
)

revokeTapleafHash := txscript.NewBaseTapLeaf(
scriptTree.SettleLeaf.Script,
).TapHash()

tapTree := scriptTree.TapscriptTree
revokeIdx := tapTree.LeafProofIndex[revokeTapleafHash]
revokeMerkleProof := tapTree.LeafMerkleProofs[revokeIdx]
revokeControlBlock := revokeMerkleProof.ToControlBlock(
&input.TaprootNUMSKey,
)

ctrlBytes, _ := revokeControlBlock.ToBytes()

toRemoteSignDesc = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: toRemoteKeyLoc,
PubKey: toRemotePK,
},
WitnessScript: scriptTree.SettleLeaf.Script,
SignMethod: input.TaprootScriptSpendSignMethod, //nolint:lll
Output: &wire.TxOut{
Value: toRemoteAmt,
PkScript: pkScript,
},
HashType: txscript.SigHashDefault,
InputIndex: 1,
ControlBlock: ctrlBytes,
}
} else {
toRemoteSignDesc = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: toRemoteKeyLoc,
PubKey: toRemotePK,
},
Output: &wire.TxOut{
Value: toRemoteAmt,
},
HashType: txscript.SigHashAll,
}
}

breachInfo.LocalOutputSignDesc = toRemoteSignDesc
breachTxn.AddTxOut(toRemoteSignDesc.Output)
}
Expand Down Expand Up @@ -248,6 +332,7 @@ func TestBackupTask(t *testing.T) {
channeldb.SingleFunderBit,
channeldb.SingleFunderTweaklessBit,
channeldb.AnchorOutputsBit,
channeldb.SimpleTaprootFeatureBit,
}

var backupTaskTests []backupTaskTest
Expand Down Expand Up @@ -281,6 +366,15 @@ func TestBackupTask(t *testing.T) {
expSweepCommitRewardRemote = 98385
sweepFeeRateNoRewardRemoteDust = 225400
sweepFeeRateRewardRemoteDust = 174100
} else if chanType.IsTaproot() {
expSweepCommitNoRewardBoth = 299167
expSweepCommitNoRewardLocal = 199469
expSweepCommitNoRewardRemote = 99532
sweepFeeRateNoRewardRemoteDust = 213200
expSweepCommitRewardBoth = 295995
expSweepCommitRewardLocal = 197297
expSweepCommitRewardRemote = 98360
sweepFeeRateRewardRemoteDust = 167000
}

backupTaskTests = append(backupTaskTests, []backupTaskTest{
Expand Down
61 changes: 50 additions & 11 deletions watchtower/wtclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ var (
waitTime = 5 * time.Second

defaultTxPolicy = wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
BlobType: blob.TypeAltruistTaprootCommit,
SweepFeeRate: wtpolicy.DefaultSweepFeeRate,
}

highSweepRateTxPolicy = wtpolicy.TxPolicy{
BlobType: blob.TypeAltruistCommit,
BlobType: blob.TypeAltruistTaprootCommit,
SweepFeeRate: 1000000, // The high sweep fee creates dust.
}
)
Expand Down Expand Up @@ -226,17 +226,25 @@ func (c *mockChannel) createRemoteCommitTx(t *testing.T) {
t.Helper()

// Construct the to-local witness script.
toLocalScript, err := input.CommitScriptToSelf(
toLocalScriptTree, err := input.NewLocalCommitScriptTree(
c.csvDelay, c.toLocalPK, c.revPK,
)
require.NoError(t, err, "unable to create to-local script")

// Construct the to-remote witness script.
toRemoteScriptTree, err := input.NewRemoteCommitScriptTree(c.toRemotePK)
require.NoError(t, err, "unable to create to-remote script")

// Compute the to-local witness script hash.
toLocalScriptHash, err := input.WitnessScriptHash(toLocalScript)
toLocalScriptHash, err := input.PayToTaprootScript(
toLocalScriptTree.TaprootKey,
)
require.NoError(t, err, "unable to create to-local witness script hash")

// Compute the to-remote witness script hash.
toRemoteScriptHash, err := input.CommitScriptUnencumbered(c.toRemotePK)
toRemoteScriptHash, err := input.PayToTaprootScript(
toRemoteScriptTree.TaprootKey,
)
require.NoError(t, err, "unable to create to-remote script")

// Construct the remote commitment txn, containing the to-local and
Expand All @@ -261,16 +269,31 @@ func (c *mockChannel) createRemoteCommitTx(t *testing.T) {
PkScript: toLocalScriptHash,
})

revokeTapleafHash := txscript.NewBaseTapLeaf(
toLocalScriptTree.RevocationLeaf.Script,
).TapHash()
tapTree := toLocalScriptTree.TapscriptTree
revokeIdx := tapTree.LeafProofIndex[revokeTapleafHash]
revokeMerkleProof := tapTree.LeafMerkleProofs[revokeIdx]
revokeControlBlock := revokeMerkleProof.ToControlBlock(
&input.TaprootNUMSKey,
)

ctrlBytes, err := revokeControlBlock.ToBytes()
require.NoError(t, err)

// Create the sign descriptor used to sign for the to-local
// input.
toLocalSignDesc = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: c.revKeyLoc,
PubKey: c.revPK,
},
WitnessScript: toLocalScript,
WitnessScript: toLocalScriptTree.RevocationLeaf.Script,
Output: commitTxn.TxOut[outputIndex],
HashType: txscript.SigHashAll,
HashType: txscript.SigHashDefault,
SignMethod: input.TaprootScriptSpendSignMethod,
ControlBlock: ctrlBytes,
}
outputIndex++
}
Expand All @@ -280,16 +303,30 @@ func (c *mockChannel) createRemoteCommitTx(t *testing.T) {
PkScript: toRemoteScriptHash,
})

toRemoteTapleafHash := txscript.NewBaseTapLeaf(
toRemoteScriptTree.SettleLeaf.Script,
).TapHash()
tapTree := toRemoteScriptTree.TapscriptTree
remoteIdx := tapTree.LeafProofIndex[toRemoteTapleafHash]
remoteMerkleProof := tapTree.LeafMerkleProofs[remoteIdx]
remoteControlBlock := remoteMerkleProof.ToControlBlock(
&input.TaprootNUMSKey,
)

ctrlBytes, _ := remoteControlBlock.ToBytes()

// Create the sign descriptor used to sign for the to-remote
// input.
toRemoteSignDesc = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
KeyLocator: c.toRemoteKeyLoc,
PubKey: c.toRemotePK,
},
WitnessScript: toRemoteScriptHash,
WitnessScript: toRemoteScriptTree.SettleLeaf.Script,
Output: commitTxn.TxOut[outputIndex],
HashType: txscript.SigHashAll,
HashType: txscript.SigHashDefault,
SignMethod: input.TaprootScriptSpendSignMethod,
ControlBlock: ctrlBytes,
}
outputIndex++
}
Expand Down Expand Up @@ -525,7 +562,7 @@ func newHarness(t *testing.T, cfg harnessCfg) *testHarness {

_, retribution := h.channelFromID(id).getState(commitHeight)

return retribution, channeldb.SingleFunderBit, nil
return retribution, channeldb.SimpleTaprootFeatureBit, nil
}

if !cfg.noServerStart {
Expand Down Expand Up @@ -694,7 +731,9 @@ func (h *testHarness) registerChannel(id uint64) {
h.t.Helper()

chanID := chanIDFromInt(id)
err := h.clientMgr.RegisterChannel(chanID, channeldb.SingleFunderBit)
err := h.clientMgr.RegisterChannel(
chanID, channeldb.SimpleTaprootFeatureBit,
)
require.NoError(h.t, err)
}

Expand Down
5 changes: 1 addition & 4 deletions watchtower/wtclient/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,10 +553,7 @@ func (m *Manager) Policy(blobType blob.Type) (wtpolicy.Policy, error) {
func (m *Manager) RegisterChannel(id lnwire.ChannelID,
chanType channeldb.ChannelType) error {

blobType := blob.TypeAltruistCommit
if chanType.HasAnchors() {
blobType = blob.TypeAltruistAnchorCommit
}
blobType := blob.TypeFromChannel(chanType)

m.clientsMu.Lock()
if _, ok := m.clients[blobType]; !ok {
Expand Down
4 changes: 3 additions & 1 deletion watchtower/wtclient/session_negotiator.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ func newSessionNegotiator(cfg *NegotiatorConfig) *sessionNegotiator {
features := []lnwire.FeatureBit{
wtwire.AltruistSessionsRequired,
}
if cfg.Policy.IsAnchorChannel() {
if cfg.Policy.IsTaprootChannel() {
features = append(features, wtwire.TaprootCommitRequired)
} else if cfg.Policy.IsAnchorChannel() {
features = append(features, wtwire.AnchorCommitRequired)
}

Expand Down

0 comments on commit ddc029c

Please sign in to comment.