Merge pull request #6680 from guggero/compute-input-script

Taproot: Fix p2tr support in `ComputeInputScript`
This commit is contained in:
Oliver Gugger authored and GitHub committed 2022-06-30 10:11:11 +02:00
commit 9d339f0fe2
8 files changed
+156 -22

No files matched your search

+1
View File
@@ -126,6 +126,7 @@ func testRemoteSigner(net *lntest.NetworkHarness, t *harnessTest) {
)
defer cancel()
testTaprootSendCoinsKeySpendBip86(ctxt, tt, wo, net)
testTaprootComputeInputScriptKeySpendBip86(
ctxt, tt, wo, net,
)
+110 -7
View File
@@ -46,6 +46,7 @@ func testTaproot(net *lntest.NetworkHarness, t *harnessTest) {
ctxt, cancel := context.WithTimeout(ctxb, 2*defaultTimeout)
defer cancel()
testTaprootSendCoinsKeySpendBip86(ctxt, t, net.Alice, net)
testTaprootComputeInputScriptKeySpendBip86(ctxt, t, net.Alice, net)
testTaprootSignOutputRawScriptSpend(ctxt, t, net.Alice, net)
testTaprootSignOutputRawKeySpendBip86(ctxt, t, net.Alice, net)
@@ -56,10 +57,10 @@ func testTaproot(net *lntest.NetworkHarness, t *harnessTest) {
testTaprootMuSig2CombinedLeafKeySpend(ctxt, t, net.Alice, net)
}
// testTaprootComputeInputScriptKeySpendBip86 tests sending to and spending from
// 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 testTaprootComputeInputScriptKeySpendBip86(ctxt context.Context,
func testTaprootSendCoinsKeySpendBip86(ctxt context.Context,
t *harnessTest, alice *lntest.HarnessNode, net *lntest.NetworkHarness) {
// We'll start the test by sending Alice some coins, which she'll use to
@@ -117,6 +118,108 @@ func testTaprootComputeInputScriptKeySpendBip86(ctxt context.Context,
confirmAddress(ctxt, t, net, 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) {
// 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)
// Let's create a p2tr address now.
p2trAddr, p2trPkScript := newAddrWithScript(
ctxt, t.t, 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{
Addr: p2trAddr.String(),
Amount: testAmount,
})
require.NoError(t.t, err)
txid, err := waitForTxInMempool(net.Miner.Client, defaultTimeout)
require.NoError(t.t, err)
// Wait until bob has seen the tx and considers it as owned.
p2trOutputIndex := getOutputIndex(t, net.Miner, txid, p2trAddr.String())
op := &lnrpc.OutPoint{
TxidBytes: txid[:],
OutputIndex: uint32(p2trOutputIndex),
}
assertWalletUnspent(t, alice, op)
p2trOutpoint := wire.OutPoint{
Hash: *txid,
Index: uint32(p2trOutputIndex),
}
// Mine a block to clean up the mempool.
mineBlocks(t, net, 1, 1)
// We'll send the coins back to a p2wkh address.
p2wkhAddr, p2wkhPkScript := newAddrWithScript(
ctxt, t.t, alice, lnrpc.AddressType_WITNESS_PUBKEY_HASH,
)
// Create fee estimation for a p2tr input and p2wkh output.
feeRate := chainfee.SatPerKWeight(12500)
estimator := input.TxWeightEstimator{}
estimator.AddTaprootKeySpendInput(txscript.SigHashDefault)
estimator.AddP2WKHOutput()
estimatedWeight := int64(estimator.Weight())
requiredFee := feeRate.FeeForWeight(estimatedWeight)
tx := wire.NewMsgTx(2)
tx.TxIn = []*wire.TxIn{{
PreviousOutPoint: p2trOutpoint,
}}
value := int64(testAmount - requiredFee)
tx.TxOut = []*wire.TxOut{{
PkScript: p2wkhPkScript,
Value: value,
}}
var buf bytes.Buffer
require.NoError(t.t, 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)
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,
&chainrpc.SpendRequest{
Outpoint: &chainrpc.Outpoint{
Hash: p2trOutpoint.Hash[:],
Index: p2trOutpoint.Index,
},
Script: p2trPkScript,
},
p2wkhAddr.String(),
)
}
// 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,
@@ -1043,20 +1146,20 @@ func newAddrWithScript(ctx context.Context, t *testing.T,
node *lntest.HarnessNode, addrType lnrpc.AddressType) (btcutil.Address,
[]byte) {
p2wkhResp, err := node.NewAddress(ctx, &lnrpc.NewAddressRequest{
newAddrResp, err := node.NewAddress(ctx, &lnrpc.NewAddressRequest{
Type: addrType,
})
require.NoError(t, err)
p2wkhAddr, err := btcutil.DecodeAddress(
p2wkhResp.Address, harnessNetParams,
addr, err := btcutil.DecodeAddress(
newAddrResp.Address, harnessNetParams,
)
require.NoError(t, err)
p2wkhPkScript, err := txscript.PayToAddrScript(p2wkhAddr)
pkScript, err := txscript.PayToAddrScript(addr)
require.NoError(t, err)
return p2wkhAddr, p2wkhPkScript
return addr, pkScript
}
// sendToTaprootOutput sends coins to a p2tr output of the given taproot key and