Skip to content

Commit 002787f

Browse files
Roasbeefguggero
authored andcommitted
input+lnwallet: update taproot scripts to accept optional aux leaf
In this commit, we update all the taproot scripts to also accept an optional aux leaf. This aux leaf can be used to add more redemption paths for advanced channels, or just as an extra commitment space.
1 parent 08a6c9c commit 002787f

File tree

11 files changed

+287
-99
lines changed

11 files changed

+287
-99
lines changed

input/script_utils.go

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,13 @@ type HtlcScriptTree struct {
673673
// TimeoutTapLeaf is the tapleaf for the timeout path.
674674
TimeoutTapLeaf txscript.TapLeaf
675675

676+
// AuxLeaf is an auxiliary leaf that can be used to extend the base
677+
// HTLC script tree with new spend paths, or just as extra commitment
678+
// space. When present, this leaf will always be in the left-most or
679+
// right-most area of the tapscript tree.
680+
AuxLeaf AuxTapLeaf
681+
682+
// htlcType is the type of HTLC script this is.
676683
htlcType htlcType
677684
}
678685

@@ -748,8 +755,8 @@ var _ TapscriptDescriptor = (*HtlcScriptTree)(nil)
748755
// senderHtlcTapScriptTree builds the tapscript tree which is used to anchor
749756
// the HTLC key for HTLCs on the sender's commitment.
750757
func senderHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
751-
revokeKey *btcec.PublicKey, payHash []byte,
752-
hType htlcType) (*HtlcScriptTree, error) {
758+
revokeKey *btcec.PublicKey, payHash []byte, hType htlcType,
759+
auxLeaf AuxTapLeaf) (*HtlcScriptTree, error) {
753760

754761
// First, we'll obtain the tap leaves for both the success and timeout
755762
// path.
@@ -766,11 +773,14 @@ func senderHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
766773
return nil, err
767774
}
768775

776+
tapLeaves := []txscript.TapLeaf{successTapLeaf, timeoutTapLeaf}
777+
auxLeaf.WhenSome(func(l txscript.TapLeaf) {
778+
tapLeaves = append(tapLeaves, l)
779+
})
780+
769781
// With the two leaves obtained, we'll now make the tapscript tree,
770782
// then obtain the root from that
771-
tapscriptTree := txscript.AssembleTaprootScriptTree(
772-
successTapLeaf, timeoutTapLeaf,
773-
)
783+
tapscriptTree := txscript.AssembleTaprootScriptTree(tapLeaves...)
774784

775785
tapScriptRoot := tapscriptTree.RootNode.TapHash()
776786

@@ -789,6 +799,7 @@ func senderHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
789799
},
790800
SuccessTapLeaf: successTapLeaf,
791801
TimeoutTapLeaf: timeoutTapLeaf,
802+
AuxLeaf: auxLeaf,
792803
htlcType: hType,
793804
}, nil
794805
}
@@ -822,8 +833,8 @@ func senderHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
822833
// The top level keyspend key is the revocation key, which allows a defender to
823834
// unilaterally spend the created output.
824835
func SenderHTLCScriptTaproot(senderHtlcKey, receiverHtlcKey,
825-
revokeKey *btcec.PublicKey, payHash []byte,
826-
localCommit bool) (*HtlcScriptTree, error) {
836+
revokeKey *btcec.PublicKey, payHash []byte, localCommit bool,
837+
auxLeaf AuxTapLeaf) (*HtlcScriptTree, error) {
827838

828839
var hType htlcType
829840
if localCommit {
@@ -836,8 +847,8 @@ func SenderHTLCScriptTaproot(senderHtlcKey, receiverHtlcKey,
836847
// tree that includes the top level output script, as well as the two
837848
// tap leaf paths.
838849
return senderHtlcTapScriptTree(
839-
senderHtlcKey, receiverHtlcKey, revokeKey, payHash,
840-
hType,
850+
senderHtlcKey, receiverHtlcKey, revokeKey, payHash, hType,
851+
auxLeaf,
841852
)
842853
}
843854

@@ -1307,8 +1318,8 @@ func ReceiverHtlcTapLeafSuccess(receiverHtlcKey *btcec.PublicKey,
13071318
// receiverHtlcTapScriptTree builds the tapscript tree which is used to anchor
13081319
// the HTLC key for HTLCs on the receiver's commitment.
13091320
func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
1310-
revokeKey *btcec.PublicKey, payHash []byte,
1311-
cltvExpiry uint32, hType htlcType) (*HtlcScriptTree, error) {
1321+
revokeKey *btcec.PublicKey, payHash []byte, cltvExpiry uint32,
1322+
hType htlcType, auxLeaf AuxTapLeaf) (*HtlcScriptTree, error) {
13121323

13131324
// First, we'll obtain the tap leaves for both the success and timeout
13141325
// path.
@@ -1325,11 +1336,14 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
13251336
return nil, err
13261337
}
13271338

1339+
tapLeaves := []txscript.TapLeaf{timeoutTapLeaf, successTapLeaf}
1340+
auxLeaf.WhenSome(func(l txscript.TapLeaf) {
1341+
tapLeaves = append(tapLeaves, l)
1342+
})
1343+
13281344
// With the two leaves obtained, we'll now make the tapscript tree,
13291345
// then obtain the root from that
1330-
tapscriptTree := txscript.AssembleTaprootScriptTree(
1331-
timeoutTapLeaf, successTapLeaf,
1332-
)
1346+
tapscriptTree := txscript.AssembleTaprootScriptTree(tapLeaves...)
13331347

13341348
tapScriptRoot := tapscriptTree.RootNode.TapHash()
13351349

@@ -1348,6 +1362,7 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
13481362
},
13491363
SuccessTapLeaf: successTapLeaf,
13501364
TimeoutTapLeaf: timeoutTapLeaf,
1365+
AuxLeaf: auxLeaf,
13511366
htlcType: hType,
13521367
}, nil
13531368
}
@@ -1382,7 +1397,8 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey,
13821397
// the tap leaf are returned.
13831398
func ReceiverHTLCScriptTaproot(cltvExpiry uint32,
13841399
senderHtlcKey, receiverHtlcKey, revocationKey *btcec.PublicKey,
1385-
payHash []byte, ourCommit bool) (*HtlcScriptTree, error) {
1400+
payHash []byte, ourCommit bool, auxLeaf AuxTapLeaf) (*HtlcScriptTree,
1401+
error) {
13861402

13871403
var hType htlcType
13881404
if ourCommit {
@@ -1396,7 +1412,7 @@ func ReceiverHTLCScriptTaproot(cltvExpiry uint32,
13961412
// tap leaf paths.
13971413
return receiverHtlcTapScriptTree(
13981414
senderHtlcKey, receiverHtlcKey, revocationKey, payHash,
1399-
cltvExpiry, hType,
1415+
cltvExpiry, hType, auxLeaf,
14001416
)
14011417
}
14021418

@@ -1625,9 +1641,9 @@ func TaprootSecondLevelTapLeaf(delayKey *btcec.PublicKey,
16251641
}
16261642

16271643
// SecondLevelHtlcTapscriptTree construct the indexed tapscript tree needed to
1628-
// generate the taptweak to create the final output and also control block.
1629-
func SecondLevelHtlcTapscriptTree(delayKey *btcec.PublicKey,
1630-
csvDelay uint32) (*txscript.IndexedTapScriptTree, error) {
1644+
// generate the tap tweak to create the final output and also control block.
1645+
func SecondLevelHtlcTapscriptTree(delayKey *btcec.PublicKey, csvDelay uint32,
1646+
auxLeaf AuxTapLeaf) (*txscript.IndexedTapScriptTree, error) {
16311647

16321648
// First grab the second level leaf script we need to create the top
16331649
// level output.
@@ -1636,9 +1652,14 @@ func SecondLevelHtlcTapscriptTree(delayKey *btcec.PublicKey,
16361652
return nil, err
16371653
}
16381654

1655+
tapLeaves := []txscript.TapLeaf{secondLevelTapLeaf}
1656+
auxLeaf.WhenSome(func(l txscript.TapLeaf) {
1657+
tapLeaves = append(tapLeaves, l)
1658+
})
1659+
16391660
// Now that we have the sole second level script, we can create the
16401661
// tapscript tree that commits to both the leaves.
1641-
return txscript.AssembleTaprootScriptTree(secondLevelTapLeaf), nil
1662+
return txscript.AssembleTaprootScriptTree(tapLeaves...), nil
16421663
}
16431664

16441665
// TaprootSecondLevelHtlcScript is the uniform script that's used as the output
@@ -1658,12 +1679,12 @@ func SecondLevelHtlcTapscriptTree(delayKey *btcec.PublicKey,
16581679
//
16591680
// The keyspend path require knowledge of the top level revocation private key.
16601681
func TaprootSecondLevelHtlcScript(revokeKey, delayKey *btcec.PublicKey,
1661-
csvDelay uint32) (*btcec.PublicKey, error) {
1682+
csvDelay uint32, auxLeaf AuxTapLeaf) (*btcec.PublicKey, error) {
16621683

16631684
// First, we'll make the tapscript tree that commits to the redemption
16641685
// path.
16651686
tapScriptTree, err := SecondLevelHtlcTapscriptTree(
1666-
delayKey, csvDelay,
1687+
delayKey, csvDelay, auxLeaf,
16671688
)
16681689
if err != nil {
16691690
return nil, err
@@ -1688,17 +1709,21 @@ type SecondLevelScriptTree struct {
16881709

16891710
// SuccessTapLeaf is the tapleaf for the redemption path.
16901711
SuccessTapLeaf txscript.TapLeaf
1712+
1713+
// AuxLeaf is an optional leaf that can be used to extend the script
1714+
// tree.
1715+
AuxLeaf AuxTapLeaf
16911716
}
16921717

16931718
// TaprootSecondLevelScriptTree constructs the tapscript tree used to spend the
16941719
// second level HTLC output.
16951720
func TaprootSecondLevelScriptTree(revokeKey, delayKey *btcec.PublicKey,
1696-
csvDelay uint32) (*SecondLevelScriptTree, error) {
1721+
csvDelay uint32, auxLeaf AuxTapLeaf) (*SecondLevelScriptTree, error) {
16971722

16981723
// First, we'll make the tapscript tree that commits to the redemption
16991724
// path.
17001725
tapScriptTree, err := SecondLevelHtlcTapscriptTree(
1701-
delayKey, csvDelay,
1726+
delayKey, csvDelay, auxLeaf,
17021727
)
17031728
if err != nil {
17041729
return nil, err
@@ -1719,6 +1744,7 @@ func TaprootSecondLevelScriptTree(revokeKey, delayKey *btcec.PublicKey,
17191744
InternalKey: revokeKey,
17201745
},
17211746
SuccessTapLeaf: tapScriptTree.LeafMerkleProofs[0].TapLeaf,
1747+
AuxLeaf: auxLeaf,
17221748
}, nil
17231749
}
17241750

@@ -2095,6 +2121,12 @@ type CommitScriptTree struct {
20952121
// RevocationLeaf is the leaf used to spend the output with the
20962122
// revocation key signature.
20972123
RevocationLeaf txscript.TapLeaf
2124+
2125+
// AuxLeaf is an auxiliary leaf that can be used to extend the base
2126+
// commitment script tree with new spend paths, or just as extra
2127+
// commitment space. When present, this leaf will always be in the
2128+
// left-most or right-most area of the tapscript tree.
2129+
AuxLeaf AuxTapLeaf
20982130
}
20992131

21002132
// A compile time check to ensure CommitScriptTree implements the
@@ -2154,8 +2186,9 @@ func (c *CommitScriptTree) CtrlBlockForPath(path ScriptPath,
21542186

21552187
// NewLocalCommitScriptTree returns a new CommitScript tree that can be used to
21562188
// create and spend the commitment output for the local party.
2157-
func NewLocalCommitScriptTree(csvTimeout uint32,
2158-
selfKey, revokeKey *btcec.PublicKey) (*CommitScriptTree, error) {
2189+
func NewLocalCommitScriptTree(csvTimeout uint32, selfKey,
2190+
revokeKey *btcec.PublicKey, auxLeaf AuxTapLeaf) (*CommitScriptTree,
2191+
error) {
21592192

21602193
// First, we'll need to construct the tapLeaf that'll be our delay CSV
21612194
// clause.
@@ -2175,9 +2208,13 @@ func NewLocalCommitScriptTree(csvTimeout uint32,
21752208
// the two leaves, and then obtain a root from that.
21762209
delayTapLeaf := txscript.NewBaseTapLeaf(delayScript)
21772210
revokeTapLeaf := txscript.NewBaseTapLeaf(revokeScript)
2178-
tapScriptTree := txscript.AssembleTaprootScriptTree(
2179-
delayTapLeaf, revokeTapLeaf,
2180-
)
2211+
2212+
tapLeaves := []txscript.TapLeaf{delayTapLeaf, revokeTapLeaf}
2213+
auxLeaf.WhenSome(func(l txscript.TapLeaf) {
2214+
tapLeaves = append(tapLeaves, l)
2215+
})
2216+
2217+
tapScriptTree := txscript.AssembleTaprootScriptTree(tapLeaves...)
21812218
tapScriptRoot := tapScriptTree.RootNode.TapHash()
21822219

21832220
// Now that we have our root, we can arrive at the final output script
@@ -2195,6 +2232,7 @@ func NewLocalCommitScriptTree(csvTimeout uint32,
21952232
},
21962233
SettleLeaf: delayTapLeaf,
21972234
RevocationLeaf: revokeTapLeaf,
2235+
AuxLeaf: auxLeaf,
21982236
}, nil
21992237
}
22002238

@@ -2264,7 +2302,7 @@ func TaprootCommitScriptToSelf(csvTimeout uint32,
22642302
selfKey, revokeKey *btcec.PublicKey) (*btcec.PublicKey, error) {
22652303

22662304
commitScriptTree, err := NewLocalCommitScriptTree(
2267-
csvTimeout, selfKey, revokeKey,
2305+
csvTimeout, selfKey, revokeKey, NoneTapLeaf(),
22682306
)
22692307
if err != nil {
22702308
return nil, err
@@ -2593,7 +2631,7 @@ func CommitScriptToRemoteConfirmed(key *btcec.PublicKey) ([]byte, error) {
25932631
// NewRemoteCommitScriptTree constructs a new script tree for the remote party
25942632
// to sweep their funds after a hard coded 1 block delay.
25952633
func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey,
2596-
) (*CommitScriptTree, error) {
2634+
auxLeaf AuxTapLeaf) (*CommitScriptTree, error) {
25972635

25982636
// First, construct the remote party's tapscript they'll use to sweep
25992637
// their outputs.
@@ -2609,10 +2647,16 @@ func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey,
26092647
return nil, err
26102648
}
26112649

2650+
tapLeaf := txscript.NewBaseTapLeaf(remoteScript)
2651+
2652+
tapLeaves := []txscript.TapLeaf{tapLeaf}
2653+
auxLeaf.WhenSome(func(l txscript.TapLeaf) {
2654+
tapLeaves = append(tapLeaves, l)
2655+
})
2656+
26122657
// With this script constructed, we'll map that into a tapLeaf, then
26132658
// make a new tapscript root from that.
2614-
tapLeaf := txscript.NewBaseTapLeaf(remoteScript)
2615-
tapScriptTree := txscript.AssembleTaprootScriptTree(tapLeaf)
2659+
tapScriptTree := txscript.AssembleTaprootScriptTree(tapLeaves...)
26162660
tapScriptRoot := tapScriptTree.RootNode.TapHash()
26172661

26182662
// Now that we have our root, we can arrive at the final output script
@@ -2629,6 +2673,7 @@ func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey,
26292673
InternalKey: &TaprootNUMSKey,
26302674
},
26312675
SettleLeaf: tapLeaf,
2676+
AuxLeaf: auxLeaf,
26322677
}, nil
26332678
}
26342679

@@ -2645,9 +2690,9 @@ func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey,
26452690
// <remotepubkey> OP_CHECKSIG
26462691
// 1 OP_CHECKSEQUENCEVERIFY OP_DROP
26472692
func TaprootCommitScriptToRemote(remoteKey *btcec.PublicKey,
2648-
) (*btcec.PublicKey, error) {
2693+
auxLeaf AuxTapLeaf) (*btcec.PublicKey, error) {
26492694

2650-
commitScriptTree, err := NewRemoteCommitScriptTree(remoteKey)
2695+
commitScriptTree, err := NewRemoteCommitScriptTree(remoteKey, auxLeaf)
26512696
if err != nil {
26522697
return nil, err
26532698
}

0 commit comments

Comments
 (0)