diff --git a/input/script_utils.go b/input/script_utils.go index 19a7c5621..dabcf92ab 100644 --- a/input/script_utils.go +++ b/input/script_utils.go @@ -47,8 +47,9 @@ const TaprootNUMSHex = "02dca094751109d0bd055d03565874e8276dd53e926b44e3bd1bb" + var ( // TaprootNUMSKey is a NUMS key (nothing up my sleeves number) that has // no known private key. This was generated using the following script: - // https://github.com/lightninglabs/lightning-node-connect/tree/master/mailbox/numsgen), - // with the seed phrase "Lightning Simple Taproot". + // https://github.com/lightninglabs/lightning-node-connect/tree/ + // master/mailbox/numsgen, with the seed phrase "Lightning Simple + // Taproot". TaprootNUMSKey = mustParsePubKey(TaprootNUMSHex) ) @@ -586,7 +587,8 @@ func SenderHTLCTapLeafSuccess(receiverHtlcKey *btcec.PublicKey, // HtlcScriptTree holds the taproot output key, as well as the two script path // leaves that every taproot HTLC script depends on. type HtlcScriptTree struct { - // TaprootKey is the key that will be used to generate the taproot output. + // TaprootKey is the key that will be used to generate the taproot + // output. TaprootKey *btcec.PublicKey // SuccessTapLeaf is the tapleaf for the redemption path. @@ -1089,7 +1091,7 @@ func ReceiverHtlcTapLeafTimeout(senderHtlcKey *btcec.PublicKey, timeoutLeafScript, err := builder.Script() if err != nil { - return txscript.TapLeaf{}, nil + return txscript.TapLeaf{}, err } return txscript.NewBaseTapLeaf(timeoutLeafScript), nil @@ -1099,10 +1101,10 @@ func ReceiverHtlcTapLeafTimeout(senderHtlcKey *btcec.PublicKey, // path for an HTLC on the receiver's commitment transaction. This script // allows the receiver to redeem an HTLC with knowledge of the preimage: // -// OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 -// OP_EQUALVERIFY -// OP_CHECKSIGVERIFY -// OP_CHECKSIG +// OP_SIZE 32 OP_EQUALVERIFY OP_HASH160 +// OP_EQUALVERIFY +// OP_CHECKSIGVERIFY +// OP_CHECKSIG func ReceiverHtlcTapLeafSuccess(receiverHtlcKey *btcec.PublicKey, senderHtlcKey *btcec.PublicKey, paymentHash []byte) (txscript.TapLeaf, error) { @@ -1180,9 +1182,9 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey, } // ReceiverHTLCScriptTaproot constructs the taproot witness program (schnor -// key) for an outgoing HTLC on the receiver's version of the commitment +// key) for an incoming HTLC on the receiver's version of the commitment // transaction. This method returns the top level tweaked public key that -// commits to both the script paths. From the PoV fo teh receiver, this is an +// commits to both the script paths. From the PoV for the receiver, this is an // accepted HTLC. // // The returned key commits to a tapscript tree with two possible paths: @@ -1198,7 +1200,7 @@ func receiverHtlcTapScriptTree(senderHtlcKey, receiverHtlcKey, // OP_CHECKSIGVERIFY // OP_CHECKSIG // -// The timeout path can be be spent with a witness of: +// The timeout path can be spent with a witness of: // - // // The success path can be spent with a witness of: @@ -1247,7 +1249,8 @@ func ReceiverHTLCScriptTaprootRedeem(senderSig Signature, successControlBlock := successMerkleProof.ToControlBlock(revokeKey) // The final witness stack is: - // * + // * + // witnessStack := wire.TxWitness(make([][]byte, 5)) witnessStack[0] = maybeAppendSighash(senderSig, senderSigHash) witnessStack[1] = maybeAppendSighash(sweepSig, signDesc.HashType) @@ -1440,8 +1443,8 @@ func TaprootSecondLevelTapLeaf(delayKey *btcec.PublicKey, func SecondLevelHtlcTapscriptTree(delayKey *btcec.PublicKey, csvDelay uint32) (*txscript.IndexedTapScriptTree, error) { - // First grab the second level leaf script we need to create the top level - // output. + // First grab the second level leaf script we need to create the top + // level output. secondLevelTapLeaf, err := TaprootSecondLevelTapLeaf(delayKey, csvDelay) if err != nil { return nil, err @@ -1518,8 +1521,7 @@ func TaprootHtlcSpendRevoke(signer Signer, signDesc *SignDescriptor, } // TaprootHtlcSpendSuccess spends a second-level HTLC output via the redemption -// path. This should be used to sweep funds after the pre-image is known or the -// timeout has elapsed on the commitment transaction of the broadcaster. +// path. This should be used to sweep funds after the pre-image is known. // // NOTE: The caller MUST set the txn version, sequence number, and sign // descriptor's sig hash cache before invocation. @@ -1803,9 +1805,9 @@ func CommitScriptToSelf(csvTimeout uint32, selfKey, revokeKey *btcec.PublicKey) return builder.Script() } -// CommitScript holds the taproot output key (in this case the revocation key, -// or a NUMs point for the remote output) along with the tapscript leaf that -// can spend the output after a delay. +// CommitScriptTree holds the taproot output key (in this case the revocation +// key, or a NUMs point for the remote output) along with the tapscript leaf +// that can spend the output after a delay. type CommitScriptTree struct { // TaprootKey is the key that will be used to generate the taproot // output. @@ -1885,8 +1887,9 @@ func NewLocalCommitScriptTree(csvTimeout uint32, // TaprootCommitScriptToSelf creates the taproot witness program that commits // to the revocation (script path) and delay path (script path) in a single // taproot output key. Both the delay script and the revocation script are part -// of the tapscript tree to ensure that the internal key is always revealed. -// This ensures that a 3rd party can always sweep the set of anchor outputs. +// of the tapscript tree to ensure that the internal key (the local delay key) +// is always revealed. This ensures that a 3rd party can always sweep the set +// of anchor outputs. // // For the delay path we have the following tapscript leaf script: // @@ -1904,7 +1907,7 @@ func NewLocalCommitScriptTree(csvTimeout uint32, // // The revocation path is simply: // -// OP_CHECKSIG +// OP_DROP // OP_CHECKSIG // // The revocation path can be spent with a control block similar to the above @@ -2223,21 +2226,21 @@ func CommitScriptToRemoteConfirmed(key *btcec.PublicKey) ([]byte, error) { func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey, ) (*CommitScriptTree, error) { - // First, construct the remote party's tapscript they'll use to sweep their - // outputs. + // First, construct the remote party's tapscript they'll use to sweep + // their outputs. builder := txscript.NewScriptBuilder() builder.AddData(schnorr.SerializePubKey(remoteKey)) builder.AddOp(txscript.OP_CHECKSIG) builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY) - delayScript, err := builder.Script() + remoteScript, err := builder.Script() if err != nil { return nil, err } // With this script constructed, we'll map that into a tapLeaf, then // make a new tapscript root from that. - tapLeaf := txscript.NewBaseTapLeaf(delayScript) + tapLeaf := txscript.NewBaseTapLeaf(remoteScript) tapScriptTree := txscript.AssembleTaprootScriptTree(tapLeaf) tapScriptRoot := tapScriptTree.RootNode.TapHash() @@ -2259,7 +2262,7 @@ func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey, // output on the commitment transaction for the remote party. For the top level // key spend, we'll use a NUMs key to ensure that only the script path can be // taken. Using a set NUMs key here also means that recovery solutions can scan -// the chain given knowledge of the public key fo the remote party. We then +// the chain given knowledge of the public key for the remote party. We then // commit to a single tapscript leaf that holds the normal CSV 1 delay // script. // @@ -2272,8 +2275,6 @@ func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey, // succeeds, which then enforces our 1 CSV. The true will remain on the stack, // causing the script to pass. If the CHECKSIG fails, then a 0 will remain on // the stack. -// -// TODO(roasbeef): double check here can't pass additional stack elements? func TaprootCommitScriptToRemote(remoteKey *btcec.PublicKey, ) (*btcec.PublicKey, error) { @@ -2419,10 +2420,8 @@ func CommitScriptAnchor(key *btcec.PublicKey) ([]byte, error) { return builder.Script() } -// AnchorScriptTree holds all the contents needed to to sweep a taproot anchor +// AnchorScriptTree holds all the contents needed to sweep a taproot anchor // output on chain. -// -// TODO(roasbeef): refactor trees to reduce dedup type AnchorScriptTree struct { // TaprootKey is the key that will be used to generate the taproot // output. @@ -2441,7 +2440,9 @@ type AnchorScriptTree struct { // NewAnchorScriptTree makes a new script tree for an anchor output with the // passed anchor key. -func NewAnchorScriptTree(anchorKey *btcec.PublicKey) (*AnchorScriptTree, error) { +func NewAnchorScriptTree(anchorKey *btcec.PublicKey, +) (*AnchorScriptTree, error) { + // The main script used is just a OP_16 CSV (anyone can sweep after 16 // blocks). builder := txscript.NewScriptBuilder() diff --git a/input/taproot_test.go b/input/taproot_test.go index c6fead21e..6263e3aa0 100644 --- a/input/taproot_test.go +++ b/input/taproot_test.go @@ -29,8 +29,6 @@ type testSenderHtlcScriptTree struct { rootHash []byte htlcAmt int64 - - lockTime int32 } func newTestSenderHtlcScriptTree(t *testing.T) *testSenderHtlcScriptTree { @@ -358,7 +356,7 @@ func TestTaprootSenderHtlcSpend(t *testing.T) { valid: true, }, - // Invalid spend of timeout path, invalid reciever sig. + // Invalid spend of timeout path, invalid receiver sig. { name: "timeout spend invalid receiver sig", witnessGen: htlcSenderTimeoutWitnessGen( @@ -384,7 +382,9 @@ func TestTaprootSenderHtlcSpend(t *testing.T) { } for i, testCase := range testCases { + i := i testCase := testCase + spendTxCopy := spendTx.Copy() t.Run(testCase.name, func(t *testing.T) { @@ -419,12 +419,10 @@ func TestTaprootSenderHtlcSpend(t *testing.T) { newEngine := func() (*txscript.Engine, error) { return txscript.NewEngine( htlcScriptTree.htlcTxOut.PkScript, - spendTxCopy, 0, txscript.StandardVerifyFlags, + spendTxCopy, 0, + txscript.StandardVerifyFlags, nil, hashCache, htlcScriptTree.htlcAmt, - txscript.NewCannedPrevOutputFetcher( - htlcScriptTree.htlcTxOut.PkScript, - htlcScriptTree.htlcAmt, - ), + prevOuts, ) } assertEngineExecution(t, i, testCase.valid, newEngine) @@ -837,7 +835,8 @@ func TestTaprootReceiverHtlcSpend(t *testing.T) { valid: false, }, } - for i, testCase := range testCases { + for i, testCase := range testCases { //nolint:paralleltest + i := i testCase := testCase spendTxCopy := spendTx.Copy() @@ -877,12 +876,10 @@ func TestTaprootReceiverHtlcSpend(t *testing.T) { newEngine := func() (*txscript.Engine, error) { return txscript.NewEngine( htlcScriptTree.htlcTxOut.PkScript, - spendTxCopy, 0, txscript.StandardVerifyFlags, + spendTxCopy, 0, + txscript.StandardVerifyFlags, nil, hashCache, htlcScriptTree.htlcAmt, - txscript.NewCannedPrevOutputFetcher( - htlcScriptTree.htlcTxOut.PkScript, - htlcScriptTree.htlcAmt, - ), + prevOuts, ) } assertEngineExecution(t, i, testCase.valid, newEngine) @@ -930,6 +927,9 @@ func newTestCommitScriptTree(local bool) (*testCommitScriptTree, error) { selfKey.PubKey(), ) } + if err != nil { + return nil, err + } pkScript, err := PayToTaprootScript(commitScriptTree.TaprootKey) if err != nil { @@ -995,11 +995,12 @@ func localCommitRevokeWitGen(sigHash txscript.SigHashType, }, } + revScript := commitScriptTree.RevocationLeaf.Script signDesc := &SignDescriptor{ KeyDesc: keychain.KeyDescriptor{ PubKey: revokeKey.PubKey(), }, - WitnessScript: commitScriptTree.RevocationLeaf.Script, + WitnessScript: revScript, Output: commitScriptTree.txOut, HashType: sigHash, InputIndex: 0, @@ -1135,7 +1136,8 @@ func TestTaprootCommitScriptToSelf(t *testing.T) { }, } - for i, testCase := range testCases { + for i, testCase := range testCases { //nolint:paralleltest + i := i testCase := testCase spendTxCopy := spendTx.Copy() @@ -1169,12 +1171,11 @@ func TestTaprootCommitScriptToSelf(t *testing.T) { newEngine := func() (*txscript.Engine, error) { return txscript.NewEngine( commitScriptTree.txOut.PkScript, - spendTxCopy, 0, txscript.StandardVerifyFlags, - nil, hashCache, int64(commitScriptTree.selfAmt), - txscript.NewCannedPrevOutputFetcher( - commitScriptTree.txOut.PkScript, - int64(commitScriptTree.selfAmt), - ), + spendTxCopy, 0, + txscript.StandardVerifyFlags, nil, + hashCache, + int64(commitScriptTree.selfAmt), + prevOuts, ) } assertEngineExecution(t, i, testCase.valid, newEngine) @@ -1312,7 +1313,8 @@ func TestTaprootCommitScriptRemote(t *testing.T) { }, } - for i, testCase := range testCases { + for i, testCase := range testCases { //nolint:paralleltest + i := i testCase := testCase spendTxCopy := spendTx.Copy() @@ -1346,12 +1348,11 @@ func TestTaprootCommitScriptRemote(t *testing.T) { newEngine := func() (*txscript.Engine, error) { return txscript.NewEngine( commitScriptTree.txOut.PkScript, - spendTxCopy, 0, txscript.StandardVerifyFlags, - nil, hashCache, int64(commitScriptTree.selfAmt), - txscript.NewCannedPrevOutputFetcher( - commitScriptTree.txOut.PkScript, - int64(commitScriptTree.selfAmt), - ), + spendTxCopy, 0, + txscript.StandardVerifyFlags, nil, + hashCache, + int64(commitScriptTree.selfAmt), + prevOuts, ) } assertEngineExecution(t, i, testCase.valid, newEngine) @@ -1531,7 +1532,8 @@ func TestTaprootAnchorScript(t *testing.T) { }, } - for i, testCase := range testCases { + for i, testCase := range testCases { //nolint:paralleltest + i := i testCase := testCase spendTxCopy := spendTx.Copy() @@ -1565,12 +1567,11 @@ func TestTaprootAnchorScript(t *testing.T) { newEngine := func() (*txscript.Engine, error) { return txscript.NewEngine( anchorScriptTree.txOut.PkScript, - spendTxCopy, 0, txscript.StandardVerifyFlags, - nil, hashCache, int64(anchorScriptTree.amt), - txscript.NewCannedPrevOutputFetcher( - anchorScriptTree.txOut.PkScript, - int64(anchorScriptTree.amt), - ), + spendTxCopy, 0, + txscript.StandardVerifyFlags, + nil, hashCache, + int64(anchorScriptTree.amt), + prevOuts, ) } assertEngineExecution(t, i, testCase.valid, newEngine) @@ -1799,7 +1800,7 @@ func TestTaprootSecondLevelHtlcScript(t *testing.T) { }, { - name: "valid revocation sweep sig hash deafult", + name: "valid revocation sweep sig hash default", witnessGen: secondLevelHtlcRevokeWitnessgen( txscript.SigHashDefault, htlcScriptTree, ), @@ -1828,7 +1829,8 @@ func TestTaprootSecondLevelHtlcScript(t *testing.T) { }, } - for i, testCase := range testCases { + for i, testCase := range testCases { //nolint:paralleltest + i := i testCase := testCase spendTxCopy := spendTx.Copy() @@ -1862,12 +1864,11 @@ func TestTaprootSecondLevelHtlcScript(t *testing.T) { newEngine := func() (*txscript.Engine, error) { return txscript.NewEngine( htlcScriptTree.txOut.PkScript, - spendTxCopy, 0, txscript.StandardVerifyFlags, - nil, hashCache, int64(htlcScriptTree.amt), - txscript.NewCannedPrevOutputFetcher( - htlcScriptTree.txOut.PkScript, - int64(htlcScriptTree.amt), - ), + spendTxCopy, 0, + txscript.StandardVerifyFlags, + nil, hashCache, + int64(htlcScriptTree.amt), + prevOuts, ) } assertEngineExecution(t, i, testCase.valid, newEngine)