From 0176d58b851be73fcac4884ea031b938d0b7eefd Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 25 Aug 2022 20:50:55 +0800 Subject: [PATCH] itest: refactor `testTaproot` --- lntemp/rpc/signer.go | 13 + lntest/itest/list_on_test.go | 4 + lntest/itest/lnd_psbt_test.go | 28 - lntest/itest/lnd_taproot_test.go | 1223 +++++++++++-------------- lntest/itest/lnd_test_list_on_test.go | 4 - lntest/itest/utils.go | 30 - 6 files changed, 564 insertions(+), 738 deletions(-) diff --git a/lntemp/rpc/signer.go b/lntemp/rpc/signer.go index 4955003eb..5ca145c27 100644 --- a/lntemp/rpc/signer.go +++ b/lntemp/rpc/signer.go @@ -177,3 +177,16 @@ func (h *HarnessRPC) VerifyMessageSigner( return resp } + +// ComputeInputScript makes a RPC call to the node's SignerClient and asserts. +func (h *HarnessRPC) ComputeInputScript( + req *signrpc.SignReq) *signrpc.InputScriptResp { + + ctxt, cancel := context.WithTimeout(h.runCtx, DefaultTimeout) + defer cancel() + + resp, err := h.Signer.ComputeInputScript(ctxt, req) + h.NoError(err, "ComputeInputScript") + + return resp +} diff --git a/lntest/itest/list_on_test.go b/lntest/itest/list_on_test.go index 6576d42d4..d9e002344 100644 --- a/lntest/itest/list_on_test.go +++ b/lntest/itest/list_on_test.go @@ -465,4 +465,8 @@ var allTestCasesTemp = []*lntemp.TestCase{ Name: "cpfp", TestFunc: testCPFP, }, + { + Name: "taproot", + TestFunc: testTaproot, + }, } diff --git a/lntest/itest/lnd_psbt_test.go b/lntest/itest/lnd_psbt_test.go index 4eb614bdf..83ceed8b5 100644 --- a/lntest/itest/lnd_psbt_test.go +++ b/lntest/itest/lnd_psbt_test.go @@ -1126,34 +1126,6 @@ func assertPsbtFundSignSpend(ht *lntemp.HarnessTest, alice *node.HarnessNode, ht.Miner.AssertTxInBlock(block, &finalTxHash) } -// deriveInternalKey derives a signing key and returns its descriptor, full -// derivation path and parsed public key. -func deriveInternalKeyOld(ctx context.Context, t *harnessTest, - alice *lntest.HarnessNode) (*signrpc.KeyDescriptor, *btcec.PublicKey, - []uint32) { - - // For the next step, we need a public key. Let's use a special family - // for this. - keyDesc, err := alice.WalletKitClient.DeriveNextKey( - ctx, &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily}, - ) - require.NoError(t.t, err) - - // The DeriveNextKey returns a key from the internal 1017 scope. - fullDerivationPath := []uint32{ - hdkeychain.HardenedKeyStart + keychain.BIP0043Purpose, - hdkeychain.HardenedKeyStart + harnessNetParams.HDCoinType, - hdkeychain.HardenedKeyStart + uint32(keyDesc.KeyLoc.KeyFamily), - 0, - uint32(keyDesc.KeyLoc.KeyIndex), - } - - parsedPubKey, err := btcec.ParsePubKey(keyDesc.RawKeyBytes) - require.NoError(t.t, err) - - return keyDesc, parsedPubKey, fullDerivationPath -} - // deriveInternalKey derives a signing key and returns its descriptor, full // derivation path and parsed public key. func deriveInternalKey(ht *lntemp.HarnessTest, diff --git a/lntest/itest/lnd_taproot_test.go b/lntest/itest/lnd_taproot_test.go index c7af79bd7..384ad5024 100644 --- a/lntest/itest/lnd_taproot_test.go +++ b/lntest/itest/lnd_taproot_test.go @@ -2,7 +2,6 @@ package itest import ( "bytes" - "context" "crypto/sha256" "encoding/hex" "testing" @@ -21,6 +20,8 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/chainrpc" "github.com/lightningnetwork/lnd/lnrpc/signrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" + "github.com/lightningnetwork/lnd/lntemp" + "github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/stretchr/testify/require" @@ -44,127 +45,111 @@ var ( // testTaproot ensures that the daemon can send to and spend from taproot (p2tr) // outputs. -func testTaproot(net *lntest.NetworkHarness, t *harnessTest) { - ctxb := context.Background() +func testTaproot(ht *lntemp.HarnessTest) { + testTaprootSendCoinsKeySpendBip86(ht, ht.Alice) + testTaprootComputeInputScriptKeySpendBip86(ht, ht.Alice) + testTaprootSignOutputRawScriptSpend(ht, ht.Alice) + testTaprootSignOutputRawKeySpendBip86(ht, ht.Alice) + testTaprootSignOutputRawKeySpendRootHash(ht, ht.Alice) - longTimeout := 2 * defaultTimeout - ctxt, cancel := context.WithTimeout(ctxb, longTimeout) - testTaprootSendCoinsKeySpendBip86(ctxt, t, net.Alice, net) - testTaprootComputeInputScriptKeySpendBip86(ctxt, t, net.Alice, net) - testTaprootSignOutputRawScriptSpend(ctxt, t, net.Alice, net) - testTaprootSignOutputRawKeySpendBip86(ctxt, t, net.Alice, net) - testTaprootSignOutputRawKeySpendRootHash(ctxt, t, net.Alice, net) - cancel() + testTaprootMuSig2KeySpendBip86(ht, ht.Alice) + testTaprootMuSig2KeySpendRootHash(ht, ht.Alice) + testTaprootMuSig2ScriptSpend(ht, ht.Alice) + testTaprootMuSig2CombinedLeafKeySpend(ht, ht.Alice) - ctxt, cancel = context.WithTimeout(ctxb, longTimeout) - testTaprootMuSig2KeySpendBip86(ctxt, t, net.Alice, net) - testTaprootMuSig2KeySpendRootHash(ctxt, t, net.Alice, net) - testTaprootMuSig2ScriptSpend(ctxt, t, net.Alice, net) - testTaprootMuSig2CombinedLeafKeySpend(ctxt, t, net.Alice, net) - cancel() - - ctxt, cancel = context.WithTimeout(ctxb, longTimeout) - testTaprootImportTapscriptFullTree(ctxt, t, net.Alice, net) - testTaprootImportTapscriptPartialReveal(ctxt, t, net.Alice, net) - testTaprootImportTapscriptRootHashOnly(ctxt, t, net.Alice, net) - testTaprootImportTapscriptFullKey(ctxt, t, net.Alice, net) - cancel() + testTaprootImportTapscriptFullTree(ht, ht.Alice) + testTaprootImportTapscriptPartialReveal(ht, ht.Alice) + testTaprootImportTapscriptRootHashOnly(ht, ht.Alice) + testTaprootImportTapscriptFullKey(ht, ht.Alice) } // testTaprootSendCoinsKeySpendBip86 tests sending to and spending from // p2tr key spend only (BIP-0086) addresses through the SendCoins RPC which // internally uses the ComputeInputScript method for signing. -func testTaprootSendCoinsKeySpendBip86(ctxt context.Context, - t *harnessTest, alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootSendCoinsKeySpendBip86(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // We'll start the test by sending Alice some coins, which she'll use to // send to herself on a p2tr output. - net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, alice) + ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) // Let's create a p2tr address now. - p2trResp, err := alice.NewAddress(ctxt, &lnrpc.NewAddressRequest{ - Type: lnrpc.AddressType_TAPROOT_PUBKEY, + p2trResp := alice.RPC.NewAddress(&lnrpc.NewAddressRequest{ + Type: AddrTypeTaprootPubkey, }) - require.NoError(t.t, err) // Assert this is a segwit v1 address that starts with bcrt1p. require.Contains( - t.t, p2trResp.Address, net.Miner.ActiveNet.Bech32HRPSegwit+"1p", + ht, p2trResp.Address, ht.Miner.ActiveNet.Bech32HRPSegwit+"1p", ) // Send the coins from Alice's wallet to her own, but to the new p2tr // address. - _, err = alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ + alice.RPC.SendCoins(&lnrpc.SendCoinsRequest{ Addr: p2trResp.Address, Amount: 0.5 * btcutil.SatoshiPerBitcoin, }) - require.NoError(t.t, err) - txid, err := waitForTxInMempool(net.Miner.Client, defaultTimeout) - require.NoError(t.t, err) + txid := ht.Miner.AssertNumTxsInMempool(1)[0] // Wait until bob has seen the tx and considers it as owned. - p2trOutputIndex := getOutputIndex(t, net.Miner, txid, p2trResp.Address) + p2trOutputIndex := ht.GetOutputIndex(txid, p2trResp.Address) op := &lnrpc.OutPoint{ TxidBytes: txid[:], OutputIndex: uint32(p2trOutputIndex), } - assertWalletUnspent(t, alice, op, "") + ht.AssertUTXOInWallet(alice, op, "") // Mine a block to clean up the mempool. - mineBlocks(t, net, 1, 1) + ht.MineBlocksAndAssertNumTxes(1, 1) // Let's sweep the whole wallet to a new p2tr address, making sure we // can sign transactions with v0 and v1 inputs. - p2trResp, err = alice.NewAddress(ctxt, &lnrpc.NewAddressRequest{ + p2trResp = alice.RPC.NewAddress(&lnrpc.NewAddressRequest{ Type: lnrpc.AddressType_TAPROOT_PUBKEY, }) - require.NoError(t.t, err) - _, err = alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ + alice.RPC.SendCoins(&lnrpc.SendCoinsRequest{ Addr: p2trResp.Address, SendAll: true, }) - require.NoError(t.t, err) // Make sure the coins sent to the address are confirmed correctly, // including the confirmation notification. - confirmAddress(ctxt, t, net, alice, p2trResp.Address) + confirmAddress(ht, alice, p2trResp.Address) } -// testTaprootComputeInputScriptKeySpendBip86 tests sending to and spending -// from p2tr key spend only (BIP-0086) addresses through the ComputeInputScript -// RPC. -func testTaprootComputeInputScriptKeySpendBip86(ctxt context.Context, - t *harnessTest, alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +// testTaprootComputeInputScriptKeySpendBip86 tests sending to and spending from +// p2tr key spend only (BIP-0086) addresses through the SendCoins RPC which +// internally uses the ComputeInputScript method for signing. +func testTaprootComputeInputScriptKeySpendBip86(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { - // We'll start the test by sending Alice some coins, which she'll use to - // send to herself on a p2tr output. - net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, alice) + // We'll start the test by sending Alice some coins, which she'll use + // to send to herself on a p2tr output. + ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) // Let's create a p2tr address now. p2trAddr, p2trPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_TAPROOT_PUBKEY, + ht, alice, lnrpc.AddressType_TAPROOT_PUBKEY, ) // Send the coins from Alice's wallet to her own, but to the new p2tr // address. - _, err := alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ + req := &lnrpc.SendCoinsRequest{ Addr: p2trAddr.String(), Amount: testAmount, - }) - require.NoError(t.t, err) - - txid, err := waitForTxInMempool(net.Miner.Client, defaultTimeout) - require.NoError(t.t, err) + } + alice.RPC.SendCoins(req) // Wait until bob has seen the tx and considers it as owned. - p2trOutputIndex := getOutputIndex(t, net.Miner, txid, p2trAddr.String()) + txid := ht.Miner.AssertNumTxsInMempool(1)[0] + p2trOutputIndex := ht.GetOutputIndex(txid, p2trAddr.String()) op := &lnrpc.OutPoint{ TxidBytes: txid[:], OutputIndex: uint32(p2trOutputIndex), } - assertWalletUnspent(t, alice, op, "") + ht.AssertUTXOInWallet(alice, op, "") p2trOutpoint := wire.OutPoint{ Hash: *txid, @@ -172,11 +157,11 @@ func testTaprootComputeInputScriptKeySpendBip86(ctxt context.Context, } // Mine a block to clean up the mempool. - mineBlocks(t, net, 1, 1) + ht.MineBlocksAndAssertNumTxes(1, 1) // We'll send the coins back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -198,31 +183,29 @@ func testTaprootComputeInputScriptKeySpendBip86(ctxt context.Context, }} var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) utxoInfo := []*signrpc.TxOut{{ PkScript: p2trPkScript, Value: testAmount, }} - signResp, err := alice.SignerClient.ComputeInputScript( - ctxt, &signrpc.SignReq{ - RawTxBytes: buf.Bytes(), - SignDescs: []*signrpc.SignDescriptor{{ - Output: utxoInfo[0], - InputIndex: 0, - Sighash: uint32(txscript.SigHashDefault), - }}, - PrevOutputs: utxoInfo, - }, - ) - require.NoError(t.t, err) + signReq := &signrpc.SignReq{ + RawTxBytes: buf.Bytes(), + SignDescs: []*signrpc.SignDescriptor{{ + Output: utxoInfo[0], + InputIndex: 0, + Sighash: uint32(txscript.SigHashDefault), + }}, + PrevOutputs: utxoInfo, + } + signResp := alice.RPC.ComputeInputScript(signReq) tx.TxIn[0].Witness = signResp.InputScripts[0].Witness // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -236,41 +219,39 @@ func testTaprootComputeInputScriptKeySpendBip86(ctxt context.Context, // testTaprootSignOutputRawScriptSpend tests sending to and spending from p2tr // script addresses using the script path with the SignOutputRaw RPC. -func testTaprootSignOutputRawScriptSpend(ctxt context.Context, t *harnessTest, - alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootSignOutputRawScriptSpend(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // For the next step, we need a public key. Let's use a special family // for this. - keyDesc, err := alice.WalletKitClient.DeriveNextKey( - ctxt, &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily}, - ) - require.NoError(t.t, err) + req := &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily} + keyDesc := alice.RPC.DeriveNextKey(req) leafSigningKey, err := btcec.ParsePubKey(keyDesc.RawKeyBytes) - require.NoError(t.t, err) + require.NoError(ht, err) // Let's create a taproot script output now. This is a hash lock with a // simple preimage of "foobar". - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) // Let's add a second script output as well to test the partial reveal. - leaf2 := testScriptSchnorrSig(t.t, leafSigningKey) + leaf2 := testScriptSchnorrSig(ht.T, leafSigningKey) inclusionProof := leaf1.TapHash() tapscript := input.TapscriptPartialReveal( dummyInternalKey, leaf2, inclusionProof[:], ) taprootKey, err := tapscript.TaprootKey() - require.NoError(t.t, err) + require.NoError(ht, err) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) // Spend the output again, this time back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -294,7 +275,7 @@ func testTaprootSignOutputRawScriptSpend(ctxt context.Context, t *harnessTest, }} var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) utxoInfo := []*signrpc.TxOut{{ PkScript: p2trPkScript, @@ -304,66 +285,60 @@ func testTaprootSignOutputRawScriptSpend(ctxt context.Context, t *harnessTest, // Before we actually sign, we want to make sure that we get an error // when we try to sign for a Taproot output without specifying all UTXO // information. - _, err = alice.SignerClient.SignOutputRaw( - ctxt, &signrpc.SignReq{ - RawTxBytes: buf.Bytes(), - SignDescs: []*signrpc.SignDescriptor{{ - Output: utxoInfo[0], - InputIndex: 0, - KeyDesc: keyDesc, - Sighash: uint32(txscript.SigHashDefault), - WitnessScript: leaf2.Script, - SignMethod: signMethodTapscript, - }}, - }, - ) - require.Error(t.t, err) + signReq := &signrpc.SignReq{ + RawTxBytes: buf.Bytes(), + SignDescs: []*signrpc.SignDescriptor{{ + Output: utxoInfo[0], + InputIndex: 0, + KeyDesc: keyDesc, + Sighash: uint32(txscript.SigHashDefault), + WitnessScript: leaf2.Script, + SignMethod: signMethodTapscript, + }}, + } + err = alice.RPC.SignOutputRawErr(signReq) require.Contains( - t.t, err.Error(), "error signing taproot output, transaction "+ + ht, err.Error(), "error signing taproot output, transaction "+ "input 0 is missing its previous outpoint information", ) // We also want to make sure we get an error when we don't specify the // correct signing method. - _, err = alice.SignerClient.SignOutputRaw( - ctxt, &signrpc.SignReq{ - RawTxBytes: buf.Bytes(), - SignDescs: []*signrpc.SignDescriptor{{ - Output: utxoInfo[0], - InputIndex: 0, - KeyDesc: keyDesc, - Sighash: uint32(txscript.SigHashDefault), - WitnessScript: leaf2.Script, - }}, - PrevOutputs: utxoInfo, - }, - ) - require.Error(t.t, err) + signReq = &signrpc.SignReq{ + RawTxBytes: buf.Bytes(), + SignDescs: []*signrpc.SignDescriptor{{ + Output: utxoInfo[0], + InputIndex: 0, + KeyDesc: keyDesc, + Sighash: uint32(txscript.SigHashDefault), + WitnessScript: leaf2.Script, + }}, + PrevOutputs: utxoInfo, + } + err = alice.RPC.SignOutputRawErr(signReq) require.Contains( - t.t, err.Error(), "selected sign method witness_v0 is not "+ + ht, err.Error(), "selected sign method witness_v0 is not "+ "compatible with given pk script 5120", ) // Do the actual signing now. - signResp, err := alice.SignerClient.SignOutputRaw( - ctxt, &signrpc.SignReq{ - RawTxBytes: buf.Bytes(), - SignDescs: []*signrpc.SignDescriptor{{ - Output: utxoInfo[0], - InputIndex: 0, - KeyDesc: keyDesc, - Sighash: uint32(txscript.SigHashDefault), - WitnessScript: leaf2.Script, - SignMethod: signMethodTapscript, - }}, - PrevOutputs: utxoInfo, - }, - ) - require.NoError(t.t, err) + signReq = &signrpc.SignReq{ + RawTxBytes: buf.Bytes(), + SignDescs: []*signrpc.SignDescriptor{{ + Output: utxoInfo[0], + InputIndex: 0, + KeyDesc: keyDesc, + Sighash: uint32(txscript.SigHashDefault), + WitnessScript: leaf2.Script, + SignMethod: signMethodTapscript, + }}, + PrevOutputs: utxoInfo, + } + signResp := alice.RPC.SignOutputRaw(signReq) // We can now assemble the witness stack. controlBlockBytes, err := tapscript.ControlBlock.ToBytes() - require.NoError(t.t, err) + require.NoError(ht, err) tx.TxIn[0].Witness = wire.TxWitness{ signResp.RawSigs[0], @@ -374,7 +349,7 @@ func testTaprootSignOutputRawScriptSpend(ctxt context.Context, t *harnessTest, // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -389,18 +364,16 @@ func testTaprootSignOutputRawScriptSpend(ctxt context.Context, t *harnessTest, // testTaprootSignOutputRawKeySpendBip86 tests that a tapscript address can // also be spent using the key spend path through the SignOutputRaw RPC using a // BIP0086 key spend only commitment. -func testTaprootSignOutputRawKeySpendBip86(ctxt context.Context, - t *harnessTest, alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootSignOutputRawKeySpendBip86(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // For the next step, we need a public key. Let's use a special family // for this. - keyDesc, err := alice.WalletKitClient.DeriveNextKey( - ctxt, &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily}, - ) - require.NoError(t.t, err) + req := &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily} + keyDesc := alice.RPC.DeriveNextKey(req) internalKey, err := btcec.ParsePubKey(keyDesc.RawKeyBytes) - require.NoError(t.t, err) + require.NoError(ht, err) // We want to make sure we can still use a tweaked key, even if it ends // up being essentially double tweaked because of the taproot root hash. @@ -413,12 +386,12 @@ func testTaprootSignOutputRawKeySpendBip86(ctxt context.Context, // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) // Spend the output again, this time back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -440,27 +413,25 @@ func testTaprootSignOutputRawKeySpendBip86(ctxt context.Context, }} var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) utxoInfo := []*signrpc.TxOut{{ PkScript: p2trPkScript, Value: testAmount, }} - signResp, err := alice.SignerClient.SignOutputRaw( - ctxt, &signrpc.SignReq{ - RawTxBytes: buf.Bytes(), - SignDescs: []*signrpc.SignDescriptor{{ - Output: utxoInfo[0], - InputIndex: 0, - KeyDesc: keyDesc, - SingleTweak: dummyKeyTweak[:], - Sighash: uint32(txscript.SigHashDefault), - SignMethod: signMethodBip86, - }}, - PrevOutputs: utxoInfo, - }, - ) - require.NoError(t.t, err) + signReq := &signrpc.SignReq{ + RawTxBytes: buf.Bytes(), + SignDescs: []*signrpc.SignDescriptor{{ + Output: utxoInfo[0], + InputIndex: 0, + KeyDesc: keyDesc, + SingleTweak: dummyKeyTweak[:], + Sighash: uint32(txscript.SigHashDefault), + SignMethod: signMethodBip86, + }}, + PrevOutputs: utxoInfo, + } + signResp := alice.RPC.SignOutputRaw(signReq) tx.TxIn[0].Witness = wire.TxWitness{ signResp.RawSigs[0], @@ -469,7 +440,7 @@ func testTaprootSignOutputRawKeySpendBip86(ctxt context.Context, // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -484,18 +455,16 @@ func testTaprootSignOutputRawKeySpendBip86(ctxt context.Context, // testTaprootSignOutputRawKeySpendRootHash tests that a tapscript address can // also be spent using the key spend path through the SignOutputRaw RPC using a // tapscript root hash. -func testTaprootSignOutputRawKeySpendRootHash(ctxt context.Context, - t *harnessTest, alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootSignOutputRawKeySpendRootHash(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // For the next step, we need a public key. Let's use a special family // for this. - keyDesc, err := alice.WalletKitClient.DeriveNextKey( - ctxt, &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily}, - ) - require.NoError(t.t, err) + req := &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily} + keyDesc := alice.RPC.DeriveNextKey(req) internalKey, err := btcec.ParsePubKey(keyDesc.RawKeyBytes) - require.NoError(t.t, err) + require.NoError(ht, err) // We want to make sure we can still use a tweaked key, even if it ends // up being essentially double tweaked because of the taproot root hash. @@ -504,19 +473,19 @@ func testTaprootSignOutputRawKeySpendRootHash(ctxt context.Context, // Let's create a taproot script output now. This is a hash lock with a // simple preimage of "foobar". - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) rootHash := leaf1.TapHash() taprootKey := txscript.ComputeTaprootOutputKey(internalKey, rootHash[:]) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) // Spend the output again, this time back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -538,29 +507,26 @@ func testTaprootSignOutputRawKeySpendRootHash(ctxt context.Context, }} var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) utxoInfo := []*signrpc.TxOut{{ PkScript: p2trPkScript, Value: testAmount, }} - signResp, err := alice.SignerClient.SignOutputRaw( - ctxt, &signrpc.SignReq{ - RawTxBytes: buf.Bytes(), - SignDescs: []*signrpc.SignDescriptor{{ - Output: utxoInfo[0], - InputIndex: 0, - KeyDesc: keyDesc, - SingleTweak: dummyKeyTweak[:], - Sighash: uint32(txscript.SigHashDefault), - TapTweak: rootHash[:], - SignMethod: signMethodRootHash, - }}, - PrevOutputs: utxoInfo, - }, - ) - require.NoError(t.t, err) - + signReq := &signrpc.SignReq{ + RawTxBytes: buf.Bytes(), + SignDescs: []*signrpc.SignDescriptor{{ + Output: utxoInfo[0], + InputIndex: 0, + KeyDesc: keyDesc, + SingleTweak: dummyKeyTweak[:], + Sighash: uint32(txscript.SigHashDefault), + TapTweak: rootHash[:], + SignMethod: signMethodRootHash, + }}, + PrevOutputs: utxoInfo, + } + signResp := alice.RPC.SignOutputRaw(signReq) tx.TxIn[0].Witness = wire.TxWitness{ signResp.RawSigs[0], } @@ -568,7 +534,7 @@ func testTaprootSignOutputRawKeySpendRootHash(ctxt context.Context, // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -582,8 +548,8 @@ func testTaprootSignOutputRawKeySpendRootHash(ctxt context.Context, // testTaprootMuSig2KeySpendBip86 tests that a combined MuSig2 key can also be // used as a BIP-0086 key spend only key. -func testTaprootMuSig2KeySpendBip86(ctxt context.Context, t *harnessTest, - alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootMuSig2KeySpendBip86(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // We're not going to commit to a script. So our taproot tweak will be // empty and just specify the necessary flag. @@ -591,22 +557,20 @@ func testTaprootMuSig2KeySpendBip86(ctxt context.Context, t *harnessTest, KeySpendOnly: true, } - keyDesc1, keyDesc2, keyDesc3, allPubKeys := deriveSigningKeys( - ctxt, t, alice, - ) + keyDesc1, keyDesc2, keyDesc3, allPubKeys := deriveSigningKeys(ht, alice) _, taprootKey, sessResp1, sessResp2, sessResp3 := createMuSigSessions( - ctxt, t, alice, taprootTweak, keyDesc1, keyDesc2, keyDesc3, + ht, alice, taprootTweak, keyDesc1, keyDesc2, keyDesc3, allPubKeys, ) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) // Spend the output again, this time back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -628,7 +592,7 @@ func testTaprootMuSig2KeySpendBip86(ctxt context.Context, t *harnessTest, }} var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) utxoInfo := []*signrpc.TxOut{{ PkScript: p2trPkScript, @@ -645,66 +609,58 @@ func testTaprootMuSig2KeySpendBip86(ctxt context.Context, t *harnessTest, sigHash, err := txscript.CalcTaprootSignatureHash( sighashes, txscript.SigHashDefault, tx, 0, prevOutputFetcher, ) - require.NoError(t.t, err) + require.NoError(ht, err) // Now that we have the transaction prepared, we need to start with the // signing. We simulate all three parties here, so we need to do // everything three times. But because we're going to use session 1 to // combine everything, we don't need its response, as it will store its // own signature. - _, err = alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp1.SessionId, - MessageDigest: sigHash, - }, - ) - require.NoError(t.t, err) + signReq := &signrpc.MuSig2SignRequest{ + SessionId: sessResp1.SessionId, + MessageDigest: sigHash, + } + alice.RPC.MuSig2Sign(signReq) - signResp2, err := alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp2.SessionId, - MessageDigest: sigHash, - Cleanup: true, - }, - ) - require.NoError(t.t, err) + signReq = &signrpc.MuSig2SignRequest{ + SessionId: sessResp2.SessionId, + MessageDigest: sigHash, + Cleanup: true, + } + signResp2 := alice.RPC.MuSig2Sign(signReq) - signResp3, err := alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp3.SessionId, - MessageDigest: sigHash, - Cleanup: true, - }, - ) - require.NoError(t.t, err) + signReq = &signrpc.MuSig2SignRequest{ + SessionId: sessResp3.SessionId, + MessageDigest: sigHash, + Cleanup: true, + } + signResp3 := alice.RPC.MuSig2Sign(signReq) // Luckily only one of the signers needs to combine the signature, so // let's do that now. - combineReq1, err := alice.SignerClient.MuSig2CombineSig( - ctxt, &signrpc.MuSig2CombineSigRequest{ - SessionId: sessResp1.SessionId, - OtherPartialSignatures: [][]byte{ - signResp2.LocalPartialSignature, - signResp3.LocalPartialSignature, - }, + combineReq := &signrpc.MuSig2CombineSigRequest{ + SessionId: sessResp1.SessionId, + OtherPartialSignatures: [][]byte{ + signResp2.LocalPartialSignature, + signResp3.LocalPartialSignature, }, - ) - require.NoError(t.t, err) - require.Equal(t.t, true, combineReq1.HaveAllSignatures) - require.NotEmpty(t.t, combineReq1.FinalSignature) + } + combineResp := alice.RPC.MuSig2CombineSig(combineReq) + require.Equal(ht, true, combineResp.HaveAllSignatures) + require.NotEmpty(ht, combineResp.FinalSignature) - sig, err := schnorr.ParseSignature(combineReq1.FinalSignature) - require.NoError(t.t, err) - require.True(t.t, sig.Verify(sigHash, taprootKey)) + sig, err := schnorr.ParseSignature(combineResp.FinalSignature) + require.NoError(ht, err) + require.True(ht, sig.Verify(sigHash, taprootKey)) tx.TxIn[0].Witness = wire.TxWitness{ - combineReq1.FinalSignature, + combineResp.FinalSignature, } // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -718,35 +674,35 @@ func testTaprootMuSig2KeySpendBip86(ctxt context.Context, t *harnessTest, // testTaprootMuSig2KeySpendRootHash tests that a tapscript address can also be // spent using a MuSig2 combined key. -func testTaprootMuSig2KeySpendRootHash(ctxt context.Context, t *harnessTest, - alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootMuSig2KeySpendRootHash(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // We're going to commit to a script as well. This is a hash lock with a // simple preimage of "foobar". We need to know this upfront so, we can // specify the taproot tweak with the root hash when creating the Musig2 // signing session. - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) rootHash := leaf1.TapHash() taprootTweak := &signrpc.TaprootTweakDesc{ ScriptRoot: rootHash[:], } keyDesc1, keyDesc2, keyDesc3, allPubKeys := deriveSigningKeys( - ctxt, t, alice, + ht, alice, ) _, taprootKey, sessResp1, sessResp2, sessResp3 := createMuSigSessions( - ctxt, t, alice, taprootTweak, keyDesc1, keyDesc2, keyDesc3, + ht, alice, taprootTweak, keyDesc1, keyDesc2, keyDesc3, allPubKeys, ) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) // Spend the output again, this time back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -768,7 +724,7 @@ func testTaprootMuSig2KeySpendRootHash(ctxt context.Context, t *harnessTest, }} var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) utxoInfo := []*signrpc.TxOut{{ PkScript: p2trPkScript, @@ -785,66 +741,58 @@ func testTaprootMuSig2KeySpendRootHash(ctxt context.Context, t *harnessTest, sigHash, err := txscript.CalcTaprootSignatureHash( sighashes, txscript.SigHashDefault, tx, 0, prevOutputFetcher, ) - require.NoError(t.t, err) + require.NoError(ht, err) // Now that we have the transaction prepared, we need to start with the // signing. We simulate all three parties here, so we need to do // everything three times. But because we're going to use session 1 to // combine everything, we don't need its response, as it will store its // own signature. - _, err = alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp1.SessionId, - MessageDigest: sigHash, - }, - ) - require.NoError(t.t, err) + req := &signrpc.MuSig2SignRequest{ + SessionId: sessResp1.SessionId, + MessageDigest: sigHash, + } + alice.RPC.MuSig2Sign(req) - signResp2, err := alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp2.SessionId, - MessageDigest: sigHash, - Cleanup: true, - }, - ) - require.NoError(t.t, err) + req = &signrpc.MuSig2SignRequest{ + SessionId: sessResp2.SessionId, + MessageDigest: sigHash, + Cleanup: true, + } + signResp2 := alice.RPC.MuSig2Sign(req) - signResp3, err := alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp3.SessionId, - MessageDigest: sigHash, - Cleanup: true, - }, - ) - require.NoError(t.t, err) + req = &signrpc.MuSig2SignRequest{ + SessionId: sessResp3.SessionId, + MessageDigest: sigHash, + Cleanup: true, + } + signResp3 := alice.RPC.MuSig2Sign(req) // Luckily only one of the signers needs to combine the signature, so // let's do that now. - combineReq1, err := alice.SignerClient.MuSig2CombineSig( - ctxt, &signrpc.MuSig2CombineSigRequest{ - SessionId: sessResp1.SessionId, - OtherPartialSignatures: [][]byte{ - signResp2.LocalPartialSignature, - signResp3.LocalPartialSignature, - }, + combineReq := &signrpc.MuSig2CombineSigRequest{ + SessionId: sessResp1.SessionId, + OtherPartialSignatures: [][]byte{ + signResp2.LocalPartialSignature, + signResp3.LocalPartialSignature, }, - ) - require.NoError(t.t, err) - require.Equal(t.t, true, combineReq1.HaveAllSignatures) - require.NotEmpty(t.t, combineReq1.FinalSignature) + } + combineResp := alice.RPC.MuSig2CombineSig(combineReq) + require.Equal(ht, true, combineResp.HaveAllSignatures) + require.NotEmpty(ht, combineResp.FinalSignature) - sig, err := schnorr.ParseSignature(combineReq1.FinalSignature) - require.NoError(t.t, err) - require.True(t.t, sig.Verify(sigHash, taprootKey)) + sig, err := schnorr.ParseSignature(combineResp.FinalSignature) + require.NoError(ht, err) + require.True(ht, sig.Verify(sigHash, taprootKey)) tx.TxIn[0].Witness = wire.TxWitness{ - combineReq1.FinalSignature, + combineResp.FinalSignature, } // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -858,24 +806,24 @@ func testTaprootMuSig2KeySpendRootHash(ctxt context.Context, t *harnessTest, // testTaprootMuSig2ScriptSpend tests that a tapscript address with an internal // key that is a MuSig2 combined key can also be spent using the script path. -func testTaprootMuSig2ScriptSpend(ctxt context.Context, t *harnessTest, - alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootMuSig2ScriptSpend(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // We're going to commit to a script and spend the output using the // script. This is a hash lock with a simple preimage of "foobar". We // need to know this upfront so, we can specify the taproot tweak with // the root hash when creating the Musig2 signing session. - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) rootHash := leaf1.TapHash() taprootTweak := &signrpc.TaprootTweakDesc{ ScriptRoot: rootHash[:], } keyDesc1, keyDesc2, keyDesc3, allPubKeys := deriveSigningKeys( - ctxt, t, alice, + ht, alice, ) internalKey, taprootKey, _, _, _ := createMuSigSessions( - ctxt, t, alice, taprootTweak, keyDesc1, keyDesc2, keyDesc3, + ht, alice, taprootTweak, keyDesc1, keyDesc2, keyDesc3, allPubKeys, ) @@ -886,12 +834,12 @@ func testTaprootMuSig2ScriptSpend(ctxt context.Context, t *harnessTest, // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) // Spend the output again, this time back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -916,7 +864,7 @@ func testTaprootMuSig2ScriptSpend(ctxt context.Context, t *harnessTest, // We can now assemble the witness stack. controlBlockBytes, err := tapscript.ControlBlock.ToBytes() - require.NoError(t.t, err) + require.NoError(ht, err) tx.TxIn[0].Witness = wire.TxWitness{ []byte("foobar"), @@ -927,7 +875,7 @@ func testTaprootMuSig2ScriptSpend(ctxt context.Context, t *harnessTest, // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -941,39 +889,37 @@ func testTaprootMuSig2ScriptSpend(ctxt context.Context, t *harnessTest, // testTaprootMuSig2CombinedLeafKeySpend tests that a MuSig2 combined key can be // used for an OP_CHECKSIG inside a tap script leaf spend. -func testTaprootMuSig2CombinedLeafKeySpend(ctxt context.Context, t *harnessTest, - alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootMuSig2CombinedLeafKeySpend(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // We're using the combined MuSig2 key in a script leaf. So we need to // derive the combined key first, before we can build the script. keyDesc1, keyDesc2, keyDesc3, allPubKeys := deriveSigningKeys( - ctxt, t, alice, + ht, alice, ) - combineResp, err := alice.SignerClient.MuSig2CombineKeys( - ctxt, &signrpc.MuSig2CombineKeysRequest{ - AllSignerPubkeys: allPubKeys, - }, - ) - require.NoError(t.t, err) + req := &signrpc.MuSig2CombineKeysRequest{ + AllSignerPubkeys: allPubKeys, + } + combineResp := alice.RPC.MuSig2CombineKeys(req) combinedPubKey, err := schnorr.ParsePubKey(combineResp.CombinedKey) - require.NoError(t.t, err) + require.NoError(ht, err) // We're going to commit to a script and spend the output using the // script. This is just an OP_CHECKSIG with the combined MuSig2 public // key. - leaf := testScriptSchnorrSig(t.t, combinedPubKey) + leaf := testScriptSchnorrSig(ht.T, combinedPubKey) tapscript := input.TapscriptPartialReveal(dummyInternalKey, leaf, nil) taprootKey, err := tapscript.TaprootKey() - require.NoError(t.t, err) + require.NoError(ht, err) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) // Spend the output again, this time back to a p2wkh address. p2wkhAddr, p2wkhPkScript := newAddrWithScript( - ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) // Create fee estimation for a p2tr input and p2wkh output. @@ -997,7 +943,7 @@ func testTaprootMuSig2CombinedLeafKeySpend(ctxt context.Context, t *harnessTest, }} var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) utxoInfo := []*signrpc.TxOut{{ PkScript: p2trPkScript, @@ -1006,9 +952,9 @@ func testTaprootMuSig2CombinedLeafKeySpend(ctxt context.Context, t *harnessTest, // Do the actual signing now. _, _, sessResp1, sessResp2, sessResp3 := createMuSigSessions( - ctxt, t, alice, nil, keyDesc1, keyDesc2, keyDesc3, allPubKeys, + ht, alice, nil, keyDesc1, keyDesc2, keyDesc3, allPubKeys, ) - require.NoError(t.t, err) + require.NoError(ht, err) // We now need to create the raw sighash of the transaction, as that // will be the message we're signing collaboratively. @@ -1021,95 +967,81 @@ func testTaprootMuSig2CombinedLeafKeySpend(ctxt context.Context, t *harnessTest, sighashes, txscript.SigHashDefault, tx, 0, prevOutputFetcher, leaf, ) - require.NoError(t.t, err) + require.NoError(ht, err) // Now that we have the transaction prepared, we need to start with the // signing. We simulate all three parties here, so we need to do // everything three times. But because we're going to use session 1 to // combine everything, we don't need its response, as it will store its // own signature. - _, err = alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp1.SessionId, - MessageDigest: sigHash, - }, - ) - require.NoError(t.t, err) + signReq := &signrpc.MuSig2SignRequest{ + SessionId: sessResp1.SessionId, + MessageDigest: sigHash, + } + alice.RPC.MuSig2Sign(signReq) - signResp2, err := alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp2.SessionId, - MessageDigest: sigHash, - Cleanup: true, - }, - ) - require.NoError(t.t, err) + signReq = &signrpc.MuSig2SignRequest{ + SessionId: sessResp2.SessionId, + MessageDigest: sigHash, + Cleanup: true, + } + signResp2 := alice.RPC.MuSig2Sign(signReq) // Before we have all partial signatures, we shouldn't get a final // signature back. - combineSigResp, err := alice.SignerClient.MuSig2CombineSig( - ctxt, &signrpc.MuSig2CombineSigRequest{ - SessionId: sessResp1.SessionId, - OtherPartialSignatures: [][]byte{ - signResp2.LocalPartialSignature, - }, + combineReq := &signrpc.MuSig2CombineSigRequest{ + SessionId: sessResp1.SessionId, + OtherPartialSignatures: [][]byte{ + signResp2.LocalPartialSignature, }, - ) - require.NoError(t.t, err) - require.False(t.t, combineSigResp.HaveAllSignatures) - require.Empty(t.t, combineSigResp.FinalSignature) + } + combineSigResp := alice.RPC.MuSig2CombineSig(combineReq) + require.False(ht, combineSigResp.HaveAllSignatures) + require.Empty(ht, combineSigResp.FinalSignature) - signResp3, err := alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp3.SessionId, - MessageDigest: sigHash, - }, - ) - require.NoError(t.t, err) + signReq = &signrpc.MuSig2SignRequest{ + SessionId: sessResp3.SessionId, + MessageDigest: sigHash, + } + signResp3 := alice.RPC.MuSig2Sign(signReq) // We manually clean up session 3, just to make sure that works as well. - _, err = alice.SignerClient.MuSig2Cleanup( - ctxt, &signrpc.MuSig2CleanupRequest{ - SessionId: sessResp3.SessionId, - }, - ) - require.NoError(t.t, err) + cleanReq := &signrpc.MuSig2CleanupRequest{ + SessionId: sessResp3.SessionId, + } + alice.RPC.MuSig2Cleanup(cleanReq) // A second call to that cleaned up session should now fail with a // specific error. - _, err = alice.SignerClient.MuSig2Sign( - ctxt, &signrpc.MuSig2SignRequest{ - SessionId: sessResp3.SessionId, - MessageDigest: sigHash, - }, - ) - require.Error(t.t, err) - require.Contains(t.t, err.Error(), "not found") + signReq = &signrpc.MuSig2SignRequest{ + SessionId: sessResp3.SessionId, + MessageDigest: sigHash, + } + err = alice.RPC.MuSig2SignErr(signReq) + require.Contains(ht, err.Error(), "not found") // Luckily only one of the signers needs to combine the signature, so // let's do that now. - combineReq1, err := alice.SignerClient.MuSig2CombineSig( - ctxt, &signrpc.MuSig2CombineSigRequest{ - SessionId: sessResp1.SessionId, - OtherPartialSignatures: [][]byte{ - signResp3.LocalPartialSignature, - }, + combineReq = &signrpc.MuSig2CombineSigRequest{ + SessionId: sessResp1.SessionId, + OtherPartialSignatures: [][]byte{ + signResp3.LocalPartialSignature, }, - ) - require.NoError(t.t, err) - require.Equal(t.t, true, combineReq1.HaveAllSignatures) - require.NotEmpty(t.t, combineReq1.FinalSignature) + } + combineResp1 := alice.RPC.MuSig2CombineSig(combineReq) + require.Equal(ht, true, combineResp1.HaveAllSignatures) + require.NotEmpty(ht, combineResp1.FinalSignature) - sig, err := schnorr.ParseSignature(combineReq1.FinalSignature) - require.NoError(t.t, err) - require.True(t.t, sig.Verify(sigHash, combinedPubKey)) + sig, err := schnorr.ParseSignature(combineResp1.FinalSignature) + require.NoError(ht, err) + require.True(ht, sig.Verify(sigHash, combinedPubKey)) // We can now assemble the witness stack. controlBlockBytes, err := tapscript.ControlBlock.ToBytes() - require.NoError(t.t, err) + require.NoError(ht, err) tx.TxIn[0].Witness = wire.TxWitness{ - combineReq1.FinalSignature, + combineResp1.FinalSignature, leaf.Script, controlBlockBytes, } @@ -1117,7 +1049,7 @@ func testTaprootMuSig2CombinedLeafKeySpend(ctxt context.Context, t *harnessTest, // Serialize, weigh and publish the TX now, then make sure the // coins are sent and confirmed to the final sweep destination address. publishTxAndConfirmSweep( - ctxt, t, net, alice, tx, estimatedWeight, + ht, alice, tx, estimatedWeight, &chainrpc.SpendRequest{ Outpoint: &chainrpc.Outpoint{ Hash: p2trOutpoint.Hash[:], @@ -1131,67 +1063,64 @@ func testTaprootMuSig2CombinedLeafKeySpend(ctxt context.Context, t *harnessTest, // testTaprootImportTapscriptScriptSpend tests importing p2tr script addresses // using the script path with the full tree known. -func testTaprootImportTapscriptFullTree(ctxt context.Context, t *harnessTest, - alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootImportTapscriptFullTree(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // For the next step, we need a public key. Let's use a special family // for this. - _, internalKey, derivationPath := deriveInternalKeyOld(ctxt, t, alice) + _, internalKey, derivationPath := deriveInternalKey(ht, alice) // Let's create a taproot script output now. This is a hash lock with a // simple preimage of "foobar". - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) // Let's add a second script output as well to test the partial reveal. - leaf2 := testScriptSchnorrSig(t.t, internalKey) + leaf2 := testScriptSchnorrSig(ht.T, internalKey) tapscript := input.TapscriptFullTree(internalKey, leaf1, leaf2) tree := txscript.AssembleTaprootScriptTree(leaf1, leaf2) rootHash := tree.RootNode.TapHash() taprootKey, err := tapscript.TaprootKey() - require.NoError(t.t, err) + require.NoError(ht, err) // Import the scripts and make sure we get the same address back as we // calculated ourselves. - importResp, err := alice.WalletKitClient.ImportTapscript( - ctxt, &walletrpc.ImportTapscriptRequest{ - InternalPublicKey: schnorr.SerializePubKey(internalKey), - Script: &walletrpc.ImportTapscriptRequest_FullTree{ - FullTree: &walletrpc.TapscriptFullTree{ - AllLeaves: []*walletrpc.TapLeaf{{ - LeafVersion: uint32( - leaf1.LeafVersion, - ), - Script: leaf1.Script, - }, { - LeafVersion: uint32( - leaf2.LeafVersion, - ), - Script: leaf2.Script, - }}, - }, + req := &walletrpc.ImportTapscriptRequest{ + InternalPublicKey: schnorr.SerializePubKey(internalKey), + Script: &walletrpc.ImportTapscriptRequest_FullTree{ + FullTree: &walletrpc.TapscriptFullTree{ + AllLeaves: []*walletrpc.TapLeaf{{ + LeafVersion: uint32( + leaf1.LeafVersion, + ), + Script: leaf1.Script, + }, { + LeafVersion: uint32( + leaf2.LeafVersion, + ), + Script: leaf2.Script, + }}, }, }, - ) - require.NoError(t.t, err) + } + importResp := alice.RPC.ImportTapscript(req) calculatedAddr, err := btcutil.NewAddressTaproot( schnorr.SerializePubKey(taprootKey), harnessNetParams, ) - require.NoError(t.t, err) - require.Equal(t.t, calculatedAddr.String(), importResp.P2TrAddress) + require.NoError(ht, err) + require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) - p2trOutputRPC := &lnrpc.OutPoint{ TxidBytes: p2trOutpoint.Hash[:], OutputIndex: p2trOutpoint.Index, } - assertWalletUnspent(t, alice, p2trOutputRPC, "imported") - assertAccountBalance(t.t, alice, "imported", testAmount, 0) + ht.AssertUTXOInWallet(alice, p2trOutputRPC, "imported") + ht.AssertWalletAccountBalance(alice, "imported", testAmount, 0) // Funding a PSBT from an imported script is not yet possible. So we // basically need to add all information manually for the wallet to be @@ -1201,26 +1130,26 @@ func testTaprootImportTapscriptFullTree(ctxt context.Context, t *harnessTest, PkScript: p2trPkScript, } clearWalletImportedTapscriptBalance( - ctxt, t, alice, utxo, p2trOutpoint, internalKey, derivationPath, + ht, alice, utxo, p2trOutpoint, internalKey, derivationPath, rootHash[:], ) } // testTaprootImportTapscriptPartialReveal tests importing p2tr script addresses // for which we only know part of the tree. -func testTaprootImportTapscriptPartialReveal(ctxt context.Context, - t *harnessTest, alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootImportTapscriptPartialReveal(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // For the next step, we need a public key. Let's use a special family // for this. - _, internalKey, derivationPath := deriveInternalKeyOld(ctxt, t, alice) + _, internalKey, derivationPath := deriveInternalKey(ht, alice) // Let's create a taproot script output now. This is a hash lock with a // simple preimage of "foobar". - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) // Let's add a second script output as well to test the partial reveal. - leaf2 := testScriptSchnorrSig(t.t, internalKey) + leaf2 := testScriptSchnorrSig(ht.T, internalKey) leaf2Hash := leaf2.TapHash() tapscript := input.TapscriptPartialReveal( @@ -1228,43 +1157,41 @@ func testTaprootImportTapscriptPartialReveal(ctxt context.Context, ) rootHash := tapscript.ControlBlock.RootHash(leaf1.Script) taprootKey, err := tapscript.TaprootKey() - require.NoError(t.t, err) + require.NoError(ht, err) // Import the scripts and make sure we get the same address back as we // calculated ourselves. - importResp, err := alice.WalletKitClient.ImportTapscript( - ctxt, &walletrpc.ImportTapscriptRequest{ - InternalPublicKey: schnorr.SerializePubKey(internalKey), - Script: &walletrpc.ImportTapscriptRequest_PartialReveal{ - PartialReveal: &walletrpc.TapscriptPartialReveal{ - RevealedLeaf: &walletrpc.TapLeaf{ - LeafVersion: uint32(leaf1.LeafVersion), - Script: leaf1.Script, - }, - FullInclusionProof: leaf2Hash[:], + req := &walletrpc.ImportTapscriptRequest{ + InternalPublicKey: schnorr.SerializePubKey(internalKey), + Script: &walletrpc.ImportTapscriptRequest_PartialReveal{ + PartialReveal: &walletrpc.TapscriptPartialReveal{ + RevealedLeaf: &walletrpc.TapLeaf{ + LeafVersion: uint32(leaf1.LeafVersion), + Script: leaf1.Script, }, + FullInclusionProof: leaf2Hash[:], }, }, - ) - require.NoError(t.t, err) + } + importResp := alice.RPC.ImportTapscript(req) calculatedAddr, err := btcutil.NewAddressTaproot( schnorr.SerializePubKey(taprootKey), harnessNetParams, ) - require.NoError(t.t, err) - require.Equal(t.t, calculatedAddr.String(), importResp.P2TrAddress) + require.NoError(ht, err) + require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) p2trOutputRPC := &lnrpc.OutPoint{ TxidBytes: p2trOutpoint.Hash[:], OutputIndex: p2trOutpoint.Index, } - assertWalletUnspent(t, alice, p2trOutputRPC, "imported") - assertAccountBalance(t.t, alice, "imported", testAmount, 0) + ht.AssertUTXOInWallet(alice, p2trOutputRPC, "imported") + ht.AssertWalletAccountBalance(alice, "imported", testAmount, 0) // Funding a PSBT from an imported script is not yet possible. So we // basically need to add all information manually for the wallet to be @@ -1274,58 +1201,56 @@ func testTaprootImportTapscriptPartialReveal(ctxt context.Context, PkScript: p2trPkScript, } clearWalletImportedTapscriptBalance( - ctxt, t, alice, utxo, p2trOutpoint, internalKey, derivationPath, + ht, alice, utxo, p2trOutpoint, internalKey, derivationPath, rootHash, ) } // testTaprootImportTapscriptRootHashOnly tests importing p2tr script addresses // for which we only know the root hash. -func testTaprootImportTapscriptRootHashOnly(ctxt context.Context, - t *harnessTest, alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootImportTapscriptRootHashOnly(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // For the next step, we need a public key. Let's use a special family // for this. - _, internalKey, derivationPath := deriveInternalKeyOld(ctxt, t, alice) + _, internalKey, derivationPath := deriveInternalKey(ht, alice) // Let's create a taproot script output now. This is a hash lock with a // simple preimage of "foobar". - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) rootHash := leaf1.TapHash() tapscript := input.TapscriptRootHashOnly(internalKey, rootHash[:]) taprootKey, err := tapscript.TaprootKey() - require.NoError(t.t, err) + require.NoError(ht, err) // Import the scripts and make sure we get the same address back as we // calculated ourselves. - importResp, err := alice.WalletKitClient.ImportTapscript( - ctxt, &walletrpc.ImportTapscriptRequest{ - InternalPublicKey: schnorr.SerializePubKey(internalKey), - Script: &walletrpc.ImportTapscriptRequest_RootHashOnly{ - RootHashOnly: rootHash[:], - }, + req := &walletrpc.ImportTapscriptRequest{ + InternalPublicKey: schnorr.SerializePubKey(internalKey), + Script: &walletrpc.ImportTapscriptRequest_RootHashOnly{ + RootHashOnly: rootHash[:], }, - ) - require.NoError(t.t, err) + } + importResp := alice.RPC.ImportTapscript(req) calculatedAddr, err := btcutil.NewAddressTaproot( schnorr.SerializePubKey(taprootKey), harnessNetParams, ) - require.NoError(t.t, err) - require.Equal(t.t, calculatedAddr.String(), importResp.P2TrAddress) + require.NoError(ht, err) + require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) p2trOutputRPC := &lnrpc.OutPoint{ TxidBytes: p2trOutpoint.Hash[:], OutputIndex: p2trOutpoint.Index, } - assertWalletUnspent(t, alice, p2trOutputRPC, "imported") - assertAccountBalance(t.t, alice, "imported", testAmount, 0) + ht.AssertUTXOInWallet(alice, p2trOutputRPC, "imported") + ht.AssertWalletAccountBalance(alice, "imported", testAmount, 0) // Funding a PSBT from an imported script is not yet possible. So we // basically need to add all information manually for the wallet to be @@ -1335,58 +1260,56 @@ func testTaprootImportTapscriptRootHashOnly(ctxt context.Context, PkScript: p2trPkScript, } clearWalletImportedTapscriptBalance( - ctxt, t, alice, utxo, p2trOutpoint, internalKey, derivationPath, + ht, alice, utxo, p2trOutpoint, internalKey, derivationPath, rootHash[:], ) } // testTaprootImportTapscriptFullKey tests importing p2tr script addresses for // which we only know the full Taproot key. -func testTaprootImportTapscriptFullKey(ctxt context.Context, t *harnessTest, - alice *lntest.HarnessNode, net *lntest.NetworkHarness) { +func testTaprootImportTapscriptFullKey(ht *lntemp.HarnessTest, + alice *node.HarnessNode) { // For the next step, we need a public key. Let's use a special family // for this. - _, internalKey, derivationPath := deriveInternalKeyOld(ctxt, t, alice) + _, internalKey, derivationPath := deriveInternalKey(ht, alice) // Let's create a taproot script output now. This is a hash lock with a // simple preimage of "foobar". - leaf1 := testScriptHashLock(t.t, []byte("foobar")) + leaf1 := testScriptHashLock(ht.T, []byte("foobar")) tapscript := input.TapscriptFullTree(internalKey, leaf1) rootHash := leaf1.TapHash() taprootKey, err := tapscript.TaprootKey() - require.NoError(t.t, err) + require.NoError(ht, err) // Import the scripts and make sure we get the same address back as we // calculated ourselves. - importResp, err := alice.WalletKitClient.ImportTapscript( - ctxt, &walletrpc.ImportTapscriptRequest{ - InternalPublicKey: schnorr.SerializePubKey(taprootKey), - Script: &walletrpc.ImportTapscriptRequest_FullKeyOnly{ - FullKeyOnly: true, - }, + req := &walletrpc.ImportTapscriptRequest{ + InternalPublicKey: schnorr.SerializePubKey(taprootKey), + Script: &walletrpc.ImportTapscriptRequest_FullKeyOnly{ + FullKeyOnly: true, }, - ) - require.NoError(t.t, err) + } + importResp := alice.RPC.ImportTapscript(req) calculatedAddr, err := btcutil.NewAddressTaproot( schnorr.SerializePubKey(taprootKey), harnessNetParams, ) - require.NoError(t.t, err) - require.Equal(t.t, calculatedAddr.String(), importResp.P2TrAddress) + require.NoError(ht, err) + require.Equal(ht, calculatedAddr.String(), importResp.P2TrAddress) // Send some coins to the generated tapscript address. p2trOutpoint, p2trPkScript := sendToTaprootOutput( - ctxt, t, net, alice, taprootKey, testAmount, + ht, alice, taprootKey, testAmount, ) p2trOutputRPC := &lnrpc.OutPoint{ TxidBytes: p2trOutpoint.Hash[:], OutputIndex: p2trOutpoint.Index, } - assertWalletUnspent(t, alice, p2trOutputRPC, "imported") - assertAccountBalance(t.t, alice, "imported", testAmount, 0) + ht.AssertUTXOInWallet(alice, p2trOutputRPC, "imported") + ht.AssertWalletAccountBalance(alice, "imported", testAmount, 0) // Funding a PSBT from an imported script is not yet possible. So we // basically need to add all information manually for the wallet to be @@ -1396,20 +1319,20 @@ func testTaprootImportTapscriptFullKey(ctxt context.Context, t *harnessTest, PkScript: p2trPkScript, } clearWalletImportedTapscriptBalance( - ctxt, t, alice, utxo, p2trOutpoint, internalKey, derivationPath, + ht, alice, utxo, p2trOutpoint, internalKey, derivationPath, rootHash[:], ) } // clearWalletImportedTapscriptBalance manually assembles and then attempts to // sign a TX to sweep funds from an imported tapscript address. -func clearWalletImportedTapscriptBalance(ctx context.Context, t *harnessTest, - node *lntest.HarnessNode, utxo *wire.TxOut, outPoint wire.OutPoint, +func clearWalletImportedTapscriptBalance(ht *lntemp.HarnessTest, + hn *node.HarnessNode, utxo *wire.TxOut, outPoint wire.OutPoint, internalKey *btcec.PublicKey, derivationPath []uint32, rootHash []byte) { _, sweepPkScript := newAddrWithScript( - ctx, t.t, node, lnrpc.AddressType_WITNESS_PUBKEY_HASH, + ht, hn, lnrpc.AddressType_WITNESS_PUBKEY_HASH, ) output := &wire.TxOut{ @@ -1420,7 +1343,7 @@ func clearWalletImportedTapscriptBalance(ctx context.Context, t *harnessTest, []*wire.OutPoint{&outPoint}, []*wire.TxOut{output}, 2, 0, []uint32{0}, ) - require.NoError(t.t, err) + require.NoError(ht, err) // We have everything we need to know to sign the PSBT. in := &packet.Inputs[0] @@ -1437,44 +1360,38 @@ func clearWalletImportedTapscriptBalance(ctx context.Context, t *harnessTest, in.WitnessUtxo = utxo var buf bytes.Buffer - require.NoError(t.t, packet.Serialize(&buf)) + require.NoError(ht, packet.Serialize(&buf)) // Sign the manually funded PSBT now. - signResp, err := node.WalletKitClient.SignPsbt( - ctx, &walletrpc.SignPsbtRequest{ - FundedPsbt: buf.Bytes(), - }, - ) - require.NoError(t.t, err) + signResp := hn.RPC.SignPsbt(&walletrpc.SignPsbtRequest{ + FundedPsbt: buf.Bytes(), + }) signedPacket, err := psbt.NewFromRawBytes( bytes.NewReader(signResp.SignedPsbt), false, ) - require.NoError(t.t, err) + require.NoError(ht, err) // We should be able to finalize the PSBT and extract the sweep TX now. err = psbt.MaybeFinalizeAll(signedPacket) - require.NoError(t.t, err) + require.NoError(ht, err) sweepTx, err := psbt.Extract(signedPacket) - require.NoError(t.t, err) + require.NoError(ht, err) buf.Reset() err = sweepTx.Serialize(&buf) - require.NoError(t.t, err) + require.NoError(ht, err) // Publish the sweep transaction and then mine it as well. - _, err = node.WalletKitClient.PublishTransaction( - ctx, &walletrpc.Transaction{ - TxHex: buf.Bytes(), - }, - ) - require.NoError(t.t, err) + hn.RPC.PublishTransaction(&walletrpc.Transaction{ + TxHex: buf.Bytes(), + }) // Mine one block which should contain the sweep transaction. - block := mineBlocks(t, t.lndHarness, 1, 1)[0] + block := ht.MineBlocksAndAssertNumTxes(1, 1)[0] sweepTxHash := sweepTx.TxHash() - assertTxInBlock(t, block, &sweepTxHash) + ht.Miner.AssertTxInBlock(block, &sweepTxHash) } // testScriptHashLock returns a simple bitcoin script that locks the funds to @@ -1504,53 +1421,45 @@ func testScriptSchnorrSig(t *testing.T, } // newAddrWithScript returns a new address and its pkScript. -func newAddrWithScript(ctx context.Context, t *testing.T, - node *lntest.HarnessNode, addrType lnrpc.AddressType) (btcutil.Address, - []byte) { +func newAddrWithScript(ht *lntemp.HarnessTest, node *node.HarnessNode, + addrType lnrpc.AddressType) (btcutil.Address, []byte) { - newAddrResp, err := node.NewAddress(ctx, &lnrpc.NewAddressRequest{ + p2wkhResp := node.RPC.NewAddress(&lnrpc.NewAddressRequest{ Type: addrType, }) - require.NoError(t, err) - - addr, err := btcutil.DecodeAddress( - newAddrResp.Address, harnessNetParams, + p2wkhAddr, err := btcutil.DecodeAddress( + p2wkhResp.Address, harnessNetParams, ) - require.NoError(t, err) + require.NoError(ht, err) - pkScript, err := txscript.PayToAddrScript(addr) - require.NoError(t, err) + p2wkhPkScript, err := txscript.PayToAddrScript(p2wkhAddr) + require.NoError(ht, err) - return addr, pkScript + return p2wkhAddr, p2wkhPkScript } // sendToTaprootOutput sends coins to a p2tr output of the given taproot key and // mines a block to confirm the coins. -func sendToTaprootOutput(ctx context.Context, t *harnessTest, - net *lntest.NetworkHarness, node *lntest.HarnessNode, +func sendToTaprootOutput(ht *lntemp.HarnessTest, hn *node.HarnessNode, taprootKey *btcec.PublicKey, amt int64) (wire.OutPoint, []byte) { tapScriptAddr, err := btcutil.NewAddressTaproot( schnorr.SerializePubKey(taprootKey), harnessNetParams, ) - require.NoError(t.t, err) + require.NoError(ht, err) p2trPkScript, err := txscript.PayToAddrScript(tapScriptAddr) - require.NoError(t.t, err) + require.NoError(ht, err) // Send some coins to the generated tapscript address. - _, err = node.SendCoins(ctx, &lnrpc.SendCoinsRequest{ + req := &lnrpc.SendCoinsRequest{ Addr: tapScriptAddr.String(), Amount: amt, - }) - require.NoError(t.t, err) + } + hn.RPC.SendCoins(req) // Wait until the TX is found in the mempool. - txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - require.NoError(t.t, err) - - p2trOutputIndex := getOutputIndex( - t, net.Miner, txid, tapScriptAddr.String(), - ) + txid := ht.Miner.AssertNumTxsInMempool(1)[0] + p2trOutputIndex := ht.GetOutputIndex(txid, tapScriptAddr.String()) p2trOutpoint := wire.OutPoint{ Hash: *txid, Index: uint32(p2trOutputIndex), @@ -1559,14 +1468,11 @@ func sendToTaprootOutput(ctx context.Context, t *harnessTest, // Make sure the transaction is recognized by our wallet and has the // correct output type. var outputDetail *lnrpc.OutputDetail - walletTxns, err := node.GetTransactions( - ctx, &lnrpc.GetTransactionsRequest{ - StartHeight: 0, - EndHeight: -1, - }, - ) - require.NoError(t.t, err) - require.NotEmpty(t.t, walletTxns.Transactions) + walletTxns := hn.RPC.GetTransactions(&lnrpc.GetTransactionsRequest{ + StartHeight: 0, + EndHeight: -1, + }) + require.NotEmpty(ht, walletTxns.Transactions) for _, tx := range walletTxns.Transactions { if tx.TxHash != txid.String() { continue @@ -1581,14 +1487,14 @@ func sendToTaprootOutput(ctx context.Context, t *harnessTest, break } } - require.NotNil(t.t, outputDetail, "transaction not found in wallet") + require.NotNil(ht, outputDetail, "transaction not found in wallet") require.Equal( - t.t, lnrpc.OutputScriptType_SCRIPT_TYPE_WITNESS_V1_TAPROOT, + ht, lnrpc.OutputScriptType_SCRIPT_TYPE_WITNESS_V1_TAPROOT, outputDetail.OutputType, ) // Clear the mempool. - mineBlocks(t, net, 1, 1) + ht.MineBlocksAndAssertNumTxes(1, 1) return p2trOutpoint, p2trPkScript } @@ -1597,158 +1503,134 @@ func sendToTaprootOutput(ctx context.Context, t *harnessTest, // after checking its weight against an estimate. After asserting the given // spend request, the given sweep address' balance is verified to be seen as // funds belonging to the wallet. -func publishTxAndConfirmSweep(ctx context.Context, t *harnessTest, - net *lntest.NetworkHarness, node *lntest.HarnessNode, tx *wire.MsgTx, - estimatedWeight int64, spendRequest *chainrpc.SpendRequest, - sweepAddr string) { +func publishTxAndConfirmSweep(ht *lntemp.HarnessTest, node *node.HarnessNode, + tx *wire.MsgTx, estimatedWeight int64, + spendRequest *chainrpc.SpendRequest, sweepAddr string) { // Before we publish the tx that spends the p2tr transaction, we want to // register a spend listener that we expect to fire after mining the // block. - _, currentHeight, err := net.Miner.Client.GetBestBlock() - require.NoError(t.t, err) + _, currentHeight := ht.Miner.GetBestBlock() // For a Taproot output we cannot leave the outpoint empty. Let's make // sure the API returns the correct error here. - spendClient, err := node.ChainClient.RegisterSpendNtfn( - ctx, &chainrpc.SpendRequest{ - Script: spendRequest.Script, - HeightHint: uint32(currentHeight), - }, - ) - require.NoError(t.t, err) + req := &chainrpc.SpendRequest{ + Script: spendRequest.Script, + HeightHint: uint32(currentHeight), + } + spendClient := node.RPC.RegisterSpendNtfn(req) // The error is only thrown when trying to read a message. - _, err = spendClient.Recv() + _, err := spendClient.Recv() require.Contains( - t.t, err.Error(), + ht, err.Error(), "cannot register witness v1 spend request without outpoint", ) // Now try again, this time with the outpoint set. - spendClient, err = node.ChainClient.RegisterSpendNtfn( - ctx, &chainrpc.SpendRequest{ - Outpoint: spendRequest.Outpoint, - Script: spendRequest.Script, - HeightHint: uint32(currentHeight), - }, - ) - require.NoError(t.t, err) + req = &chainrpc.SpendRequest{ + Outpoint: spendRequest.Outpoint, + Script: spendRequest.Script, + HeightHint: uint32(currentHeight), + } + spendClient = node.RPC.RegisterSpendNtfn(req) var buf bytes.Buffer - require.NoError(t.t, tx.Serialize(&buf)) + require.NoError(ht, tx.Serialize(&buf)) // Since Schnorr signatures are fixed size, we must be able to estimate // the size of this transaction exactly. txWeight := blockchain.GetTransactionWeight(btcutil.NewTx(tx)) - require.Equal(t.t, estimatedWeight, txWeight) + require.Equal(ht, estimatedWeight, txWeight) - _, err = node.WalletKitClient.PublishTransaction( - ctx, &walletrpc.Transaction{ - TxHex: buf.Bytes(), - }, - ) - require.NoError(t.t, err) + txReq := &walletrpc.Transaction{ + TxHex: buf.Bytes(), + } + node.RPC.PublishTransaction(txReq) // Make sure the coins sent to the address are confirmed correctly, // including the confirmation notification. - confirmAddress(ctx, t, net, node, sweepAddr) + confirmAddress(ht, node, sweepAddr) // We now expect our spend event to go through. spendMsg, err := spendClient.Recv() - require.NoError(t.t, err) + require.NoError(ht, err) spend := spendMsg.GetSpend() - require.NotNil(t.t, spend) - require.Equal(t.t, spend.SpendingHeight, uint32(currentHeight+1)) + require.NotNil(ht, spend) + require.Equal(ht, spend.SpendingHeight, uint32(currentHeight+1)) } // confirmAddress makes sure that a transaction in the mempool spends funds to // the given address. It also checks that a confirmation notification for the // address is triggered when the transaction is mined. -func confirmAddress(ctx context.Context, t *harnessTest, - net *lntest.NetworkHarness, node *lntest.HarnessNode, +func confirmAddress(ht *lntemp.HarnessTest, hn *node.HarnessNode, addrString string) { // Wait until the tx that sends to the address is found. - txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - require.NoError(t.t, err) + txid := ht.Miner.AssertNumTxsInMempool(1)[0] // Wait until bob has seen the tx and considers it as owned. - addrOutputIndex := getOutputIndex(t, net.Miner, txid, addrString) + addrOutputIndex := ht.GetOutputIndex(txid, addrString) op := &lnrpc.OutPoint{ TxidBytes: txid[:], OutputIndex: uint32(addrOutputIndex), } - assertWalletUnspent(t, node, op, "") + ht.AssertUTXOInWallet(hn, op, "") // Before we confirm the transaction, let's register a confirmation // listener for it, which we expect to fire after mining a block. parsedAddr, err := btcutil.DecodeAddress(addrString, harnessNetParams) - require.NoError(t.t, err) + require.NoError(ht, err) addrPkScript, err := txscript.PayToAddrScript(parsedAddr) - require.NoError(t.t, err) + require.NoError(ht, err) - _, currentHeight, err := net.Miner.Client.GetBestBlock() - require.NoError(t.t, err) - - // We'll register for a conf notification, and also request the block - // that included it as well. - confClient, err := node.ChainClient.RegisterConfirmationsNtfn( - ctx, &chainrpc.ConfRequest{ - Script: addrPkScript, - Txid: txid[:], - HeightHint: uint32(currentHeight), - NumConfs: 1, - IncludeBlock: true, - }, - ) - require.NoError(t.t, err) + _, currentHeight := ht.Miner.GetBestBlock() + req := &chainrpc.ConfRequest{ + Script: addrPkScript, + Txid: txid[:], + HeightHint: uint32(currentHeight), + NumConfs: 1, + IncludeBlock: true, + } + confClient := hn.RPC.RegisterConfirmationsNtfn(req) // Mine another block to clean up the mempool. - mineBlocks(t, net, 1, 1) + ht.MineBlocksAndAssertNumTxes(1, 1) // We now expect our confirmation to go through, and also that the // block was specified. confMsg, err := confClient.Recv() - require.NoError(t.t, err) + require.NoError(ht, err) conf := confMsg.GetConf() - require.NotNil(t.t, conf) - require.Equal(t.t, conf.BlockHeight, uint32(currentHeight+1)) - require.NotNil(t.t, conf.RawBlock) + require.NotNil(ht, conf) + require.Equal(ht, conf.BlockHeight, uint32(currentHeight+1)) + require.NotNil(ht, conf.RawBlock) // We should also be able to decode the raw block. var blk wire.MsgBlock - require.NoError(t.t, blk.Deserialize(bytes.NewReader(conf.RawBlock))) + require.NoError(ht, blk.Deserialize(bytes.NewReader(conf.RawBlock))) } // deriveSigningKeys derives three signing keys and returns their descriptors, // as well as the public keys in the Schnorr serialized format. -func deriveSigningKeys(ctx context.Context, t *harnessTest, - node *lntest.HarnessNode) (*signrpc.KeyDescriptor, +func deriveSigningKeys(ht *lntemp.HarnessTest, + node *node.HarnessNode) (*signrpc.KeyDescriptor, *signrpc.KeyDescriptor, *signrpc.KeyDescriptor, [][]byte) { // For muSig2 we need multiple keys. We derive three of them from the // same wallet, just so we know we can also sign for them again. - keyDesc1, err := node.WalletKitClient.DeriveNextKey( - ctx, &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily}, - ) - require.NoError(t.t, err) + req := &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily} + keyDesc1 := node.RPC.DeriveNextKey(req) pubKey1, err := btcec.ParsePubKey(keyDesc1.RawKeyBytes) - require.NoError(t.t, err) + require.NoError(ht, err) - keyDesc2, err := node.WalletKitClient.DeriveNextKey( - ctx, &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily}, - ) - require.NoError(t.t, err) + keyDesc2 := node.RPC.DeriveNextKey(req) pubKey2, err := btcec.ParsePubKey(keyDesc2.RawKeyBytes) - require.NoError(t.t, err) + require.NoError(ht, err) - keyDesc3, err := node.WalletKitClient.DeriveNextKey( - ctx, &walletrpc.KeyReq{KeyFamily: testTaprootKeyFamily}, - ) - require.NoError(t.t, err) + keyDesc3 := node.RPC.DeriveNextKey(req) pubKey3, err := btcec.ParsePubKey(keyDesc3.RawKeyBytes) - require.NoError(t.t, err) + require.NoError(ht, err) // Now that we have all three keys we can create three sessions, one // for each of the signers. This would of course normally not happen on @@ -1766,21 +1648,19 @@ func deriveSigningKeys(ctx context.Context, t *harnessTest, // combined into a single key. The same node is used for the three signing // participants but a separate key is generated for each session. So the result // should be the same as if it were three different nodes. -func createMuSigSessions(ctx context.Context, t *harnessTest, - node *lntest.HarnessNode, taprootTweak *signrpc.TaprootTweakDesc, +func createMuSigSessions(ht *lntemp.HarnessTest, node *node.HarnessNode, + taprootTweak *signrpc.TaprootTweakDesc, keyDesc1, keyDesc2, keyDesc3 *signrpc.KeyDescriptor, allPubKeys [][]byte) (*btcec.PublicKey, *btcec.PublicKey, *signrpc.MuSig2SessionResponse, *signrpc.MuSig2SessionResponse, *signrpc.MuSig2SessionResponse) { - sessResp1, err := node.SignerClient.MuSig2CreateSession( - ctx, &signrpc.MuSig2SessionRequest{ - KeyLoc: keyDesc1.KeyLoc, - AllSignerPubkeys: allPubKeys, - TaprootTweak: taprootTweak, - }, - ) - require.NoError(t.t, err) + req := &signrpc.MuSig2SessionRequest{ + KeyLoc: keyDesc1.KeyLoc, + AllSignerPubkeys: allPubKeys, + TaprootTweak: taprootTweak, + } + sessResp1 := node.RPC.MuSig2CreateSession(req) // Now that we have the three keys in a combined form, we want to make // sure the tweaking for the taproot key worked correctly. We first need @@ -1789,7 +1669,7 @@ func createMuSigSessions(ctx context.Context, t *harnessTest, // tapHash of the script root hash. We should arrive at the same result // as the API. combinedKey, err := schnorr.ParsePubKey(sessResp1.CombinedKey) - require.NoError(t.t, err) + require.NoError(ht, err) // When combining the key without creating a session, we expect the same // combined key to be created. @@ -1804,7 +1684,7 @@ func createMuSigSessions(ctx context.Context, t *harnessTest, internalKey, err = schnorr.ParsePubKey( sessResp1.TaprootInternalKey, ) - require.NoError(t.t, err) + require.NoError(ht, err) // We now know the taproot key. The session with the tweak // applied should produce the same key! @@ -1812,82 +1692,73 @@ func createMuSigSessions(ctx context.Context, t *harnessTest, internalKey, taprootTweak.ScriptRoot, ) require.Equal( - t.t, schnorr.SerializePubKey(expectedCombinedKey), + ht, schnorr.SerializePubKey(expectedCombinedKey), schnorr.SerializePubKey(combinedKey), ) } // We should also get the same keys when just calling the // MuSig2CombineKeys RPC. - combineResp, err := node.SignerClient.MuSig2CombineKeys( - ctx, &signrpc.MuSig2CombineKeysRequest{ - AllSignerPubkeys: allPubKeys, - TaprootTweak: taprootTweak, - }, - ) - require.NoError(t.t, err) + combineReq := &signrpc.MuSig2CombineKeysRequest{ + AllSignerPubkeys: allPubKeys, + TaprootTweak: taprootTweak, + } + combineResp := node.RPC.MuSig2CombineKeys(combineReq) require.Equal( - t.t, schnorr.SerializePubKey(expectedCombinedKey), + ht, schnorr.SerializePubKey(expectedCombinedKey), combineResp.CombinedKey, ) require.Equal( - t.t, schnorr.SerializePubKey(internalKey), + ht, schnorr.SerializePubKey(internalKey), combineResp.TaprootInternalKey, ) // Everything is good so far, let's continue with creating the signing // session for the other two participants. - sessResp2, err := node.SignerClient.MuSig2CreateSession( - ctx, &signrpc.MuSig2SessionRequest{ - KeyLoc: keyDesc2.KeyLoc, - AllSignerPubkeys: allPubKeys, - OtherSignerPublicNonces: [][]byte{ - sessResp1.LocalPublicNonces, - }, - TaprootTweak: taprootTweak, + req = &signrpc.MuSig2SessionRequest{ + KeyLoc: keyDesc2.KeyLoc, + AllSignerPubkeys: allPubKeys, + OtherSignerPublicNonces: [][]byte{ + sessResp1.LocalPublicNonces, }, - ) - require.NoError(t.t, err) - require.Equal(t.t, sessResp1.CombinedKey, sessResp2.CombinedKey) + TaprootTweak: taprootTweak, + } + sessResp2 := node.RPC.MuSig2CreateSession(req) + require.Equal(ht, sessResp1.CombinedKey, sessResp2.CombinedKey) - sessResp3, err := node.SignerClient.MuSig2CreateSession( - ctx, &signrpc.MuSig2SessionRequest{ - KeyLoc: keyDesc3.KeyLoc, - AllSignerPubkeys: allPubKeys, - OtherSignerPublicNonces: [][]byte{ - sessResp1.LocalPublicNonces, - sessResp2.LocalPublicNonces, - }, - TaprootTweak: taprootTweak, + req = &signrpc.MuSig2SessionRequest{ + KeyLoc: keyDesc3.KeyLoc, + AllSignerPubkeys: allPubKeys, + OtherSignerPublicNonces: [][]byte{ + sessResp1.LocalPublicNonces, + sessResp2.LocalPublicNonces, }, - ) - require.NoError(t.t, err) - require.Equal(t.t, sessResp2.CombinedKey, sessResp3.CombinedKey) - require.Equal(t.t, true, sessResp3.HaveAllNonces) + TaprootTweak: taprootTweak, + } + sessResp3 := node.RPC.MuSig2CreateSession(req) + require.NoError(ht, err) + require.Equal(ht, sessResp2.CombinedKey, sessResp3.CombinedKey) + require.Equal(ht, true, sessResp3.HaveAllNonces) // We need to distribute the rest of the nonces. - nonceResp1, err := node.SignerClient.MuSig2RegisterNonces( - ctx, &signrpc.MuSig2RegisterNoncesRequest{ - SessionId: sessResp1.SessionId, - OtherSignerPublicNonces: [][]byte{ - sessResp2.LocalPublicNonces, - sessResp3.LocalPublicNonces, - }, + nonceReq := &signrpc.MuSig2RegisterNoncesRequest{ + SessionId: sessResp1.SessionId, + OtherSignerPublicNonces: [][]byte{ + sessResp2.LocalPublicNonces, + sessResp3.LocalPublicNonces, }, - ) - require.NoError(t.t, err) - require.Equal(t.t, true, nonceResp1.HaveAllNonces) + } + nonceResp1 := node.RPC.MuSig2RegisterNonces(nonceReq) + require.True(ht, nonceResp1.HaveAllNonces) - nonceResp2, err := node.SignerClient.MuSig2RegisterNonces( - ctx, &signrpc.MuSig2RegisterNoncesRequest{ - SessionId: sessResp2.SessionId, - OtherSignerPublicNonces: [][]byte{ - sessResp3.LocalPublicNonces, - }, + nonceReq = &signrpc.MuSig2RegisterNoncesRequest{ + SessionId: sessResp2.SessionId, + OtherSignerPublicNonces: [][]byte{ + sessResp3.LocalPublicNonces, }, - ) - require.NoError(t.t, err) - require.Equal(t.t, true, nonceResp2.HaveAllNonces) + } + nonceResp2 := node.RPC.MuSig2RegisterNonces(nonceReq) + require.True(ht, nonceResp2.HaveAllNonces) return internalKey, combinedKey, sessResp1, sessResp2, sessResp3 } diff --git a/lntest/itest/lnd_test_list_on_test.go b/lntest/itest/lnd_test_list_on_test.go index 7afb99089..eac437576 100644 --- a/lntest/itest/lnd_test_list_on_test.go +++ b/lntest/itest/lnd_test_list_on_test.go @@ -24,10 +24,6 @@ var allTestCases = []*testCase{ name: "remote signer", test: testRemoteSigner, }, - { - name: "taproot", - test: testTaproot, - }, { name: "taproot coop close", test: testTaprootCoopClose, diff --git a/lntest/itest/utils.go b/lntest/itest/utils.go index ed1d212dd..4995a0beb 100644 --- a/lntest/itest/utils.go +++ b/lntest/itest/utils.go @@ -8,9 +8,7 @@ import ( "time" "github.com/btcsuite/btcd/btcutil" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/rpcclient" - "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/input" @@ -468,31 +466,3 @@ func findTxAtHeight(t *harnessTest, height int32, return nil } - -// getOutputIndex returns the output index of the given address in the given -// transaction. -func getOutputIndex(t *harnessTest, miner *lntest.HarnessMiner, - txid *chainhash.Hash, addr string) int { - - t.t.Helper() - - // We'll then extract the raw transaction from the mempool in order to - // determine the index of the p2tr output. - tx, err := miner.Client.GetRawTransaction(txid) - require.NoError(t.t, err) - - p2trOutputIndex := -1 - for i, txOut := range tx.MsgTx().TxOut { - _, addrs, _, err := txscript.ExtractPkScriptAddrs( - txOut.PkScript, miner.ActiveNet, - ) - require.NoError(t.t, err) - - if addrs[0].String() == addr { - p2trOutputIndex = i - } - } - require.Greater(t.t, p2trOutputIndex, -1) - - return p2trOutputIndex -}