lntemp+itest: refactor testSignOutputRaw

This commit is contained in:
yyforyongyu committed 2023-01-18 10:53:56 +08:00
1 parent ab23421cd8
commit 20e454b229
5 files changed
+120 -91

No files matched your search

+23
View File
@@ -1944,3 +1944,26 @@ func (h *HarnessTest) ReceiveChannelEvent(
return nil return nil
} }
// GetOutputIndex returns the output index of the given address in the given
// transaction.
func (h *HarnessTest) GetOutputIndex(txid *chainhash.Hash, addr string) int {
// We'll then extract the raw transaction from the mempool in order to
// determine the index of the p2tr output.
tx := h.Miner.GetRawTransaction(txid)
p2trOutputIndex := -1
for i, txOut := range tx.MsgTx().TxOut {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
txOut.PkScript, h.Miner.ActiveNet,
)
require.NoError(h, err)
if addrs[0].String() == addr {
p2trOutputIndex = i
}
}
require.Greater(h, p2trOutputIndex, -1)
return p2trOutputIndex
}
+34
View File
@@ -1,6 +1,7 @@
package lntemp package lntemp
import ( import (
"bytes"
"context" "context"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
@@ -2133,3 +2134,36 @@ func (h *HarnessTest) AssertInvoiceEqual(a, b *lnrpc.Invoice) {
require.Equal(h, htlcA.Amp, htlcB.Amp) require.Equal(h, htlcA.Amp, htlcB.Amp)
} }
} }
// AssertUTXOInWallet asserts that a given UTXO can be found in the node's
// wallet.
func (h *HarnessTest) AssertUTXOInWallet(hn *node.HarnessNode,
op *lnrpc.OutPoint, account string) {
err := wait.NoError(func() error {
req := &walletrpc.ListUnspentRequest{
Account: account,
}
resp := hn.RPC.ListUnspent(req)
err := fmt.Errorf("tx with hash %x not found", op.TxidBytes)
for _, utxo := range resp.Utxos {
if !bytes.Equal(utxo.Outpoint.TxidBytes, op.TxidBytes) {
continue
}
err = fmt.Errorf("tx with output index %v not found",
op.OutputIndex)
if utxo.Outpoint.OutputIndex != op.OutputIndex {
continue
}
return nil
}
return err
}, DefaultTimeout)
require.NoErrorf(h, err, "outpoint %v not found in %s's wallet",
op, hn.Name())
}
+4
View File
@@ -445,4 +445,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
Name: "derive shared key", Name: "derive shared key",
TestFunc: testDeriveSharedKey, TestFunc: testDeriveSharedKey,
}, },
{
Name: "sign output raw",
TestFunc: testSignOutputRaw,
},
} }
+59 -87
View File
@@ -197,43 +197,35 @@ func runDeriveSharedKey(ht *lntemp.HarnessTest, alice *node.HarnessNode) {
// testSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all // testSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all
// custom ways of specifying the signing key in the key descriptor/locator. // custom ways of specifying the signing key in the key descriptor/locator.
func testSignOutputRaw(net *lntest.NetworkHarness, t *harnessTest) { func testSignOutputRaw(ht *lntemp.HarnessTest) {
runSignOutputRaw(t, net, net.Alice) runSignOutputRaw(ht, ht.Alice)
} }
// runSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all // runSignOutputRaw makes sure that the SignOutputRaw RPC can be used with all
// custom ways of specifying the signing key in the key descriptor/locator. // custom ways of specifying the signing key in the key descriptor/locator.
func runSignOutputRaw(t *harnessTest, net *lntest.NetworkHarness, func runSignOutputRaw(ht *lntemp.HarnessTest, alice *node.HarnessNode) {
alice *lntest.HarnessNode) {
ctxb := context.Background()
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
// For the next step, we need a public key. Let's use a special family // For the next step, we need a public key. Let's use a special family
// for this. We want this to be an index of zero. // for this. We want this to be an index of zero.
const testCustomKeyFamily = 44 const testCustomKeyFamily = 44
keyDesc, err := alice.WalletKitClient.DeriveNextKey( req := &walletrpc.KeyReq{
ctxt, &walletrpc.KeyReq{ KeyFamily: testCustomKeyFamily,
KeyFamily: testCustomKeyFamily, }
}, keyDesc := alice.RPC.DeriveNextKey(req)
) require.Equal(ht, int32(0), keyDesc.KeyLoc.KeyIndex)
require.NoError(t.t, err)
require.Equal(t.t, int32(0), keyDesc.KeyLoc.KeyIndex)
targetPubKey, err := btcec.ParsePubKey(keyDesc.RawKeyBytes) targetPubKey, err := btcec.ParsePubKey(keyDesc.RawKeyBytes)
require.NoError(t.t, err) require.NoError(ht, err)
// First, try with a key descriptor that only sets the public key. // First, try with a key descriptor that only sets the public key.
assertSignOutputRaw( assertSignOutputRaw(
t, net, alice, targetPubKey, &signrpc.KeyDescriptor{ ht, alice, targetPubKey, &signrpc.KeyDescriptor{
RawKeyBytes: keyDesc.RawKeyBytes, RawKeyBytes: keyDesc.RawKeyBytes,
}, },
) )
// Now try again, this time only with the (0 index!) key locator. // Now try again, this time only with the (0 index!) key locator.
assertSignOutputRaw( assertSignOutputRaw(
t, net, alice, targetPubKey, &signrpc.KeyDescriptor{ ht, alice, targetPubKey, &signrpc.KeyDescriptor{
KeyLoc: &signrpc.KeyLocator{ KeyLoc: &signrpc.KeyLocator{
KeyFamily: keyDesc.KeyLoc.KeyFamily, KeyFamily: keyDesc.KeyLoc.KeyFamily,
KeyIndex: keyDesc.KeyLoc.KeyIndex, KeyIndex: keyDesc.KeyLoc.KeyIndex,
@@ -243,29 +235,25 @@ func runSignOutputRaw(t *harnessTest, net *lntest.NetworkHarness,
// And now test everything again with a new key where we know the index // And now test everything again with a new key where we know the index
// is not 0. // is not 0.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) req = &walletrpc.KeyReq{
defer cancel() KeyFamily: testCustomKeyFamily,
keyDesc, err = alice.WalletKitClient.DeriveNextKey( }
ctxt, &walletrpc.KeyReq{ keyDesc = alice.RPC.DeriveNextKey(req)
KeyFamily: testCustomKeyFamily, require.Equal(ht, int32(1), keyDesc.KeyLoc.KeyIndex)
},
)
require.NoError(t.t, err)
require.Equal(t.t, int32(1), keyDesc.KeyLoc.KeyIndex)
targetPubKey, err = btcec.ParsePubKey(keyDesc.RawKeyBytes) targetPubKey, err = btcec.ParsePubKey(keyDesc.RawKeyBytes)
require.NoError(t.t, err) require.NoError(ht, err)
// First, try with a key descriptor that only sets the public key. // First, try with a key descriptor that only sets the public key.
assertSignOutputRaw( assertSignOutputRaw(
t, net, alice, targetPubKey, &signrpc.KeyDescriptor{ ht, alice, targetPubKey, &signrpc.KeyDescriptor{
RawKeyBytes: keyDesc.RawKeyBytes, RawKeyBytes: keyDesc.RawKeyBytes,
}, },
) )
// Now try again, this time only with the key locator. // Now try again, this time only with the key locator.
assertSignOutputRaw( assertSignOutputRaw(
t, net, alice, targetPubKey, &signrpc.KeyDescriptor{ ht, alice, targetPubKey, &signrpc.KeyDescriptor{
KeyLoc: &signrpc.KeyLocator{ KeyLoc: &signrpc.KeyLocator{
KeyFamily: keyDesc.KeyLoc.KeyFamily, KeyFamily: keyDesc.KeyLoc.KeyFamily,
KeyIndex: keyDesc.KeyLoc.KeyIndex, KeyIndex: keyDesc.KeyLoc.KeyIndex,
@@ -277,53 +265,44 @@ func runSignOutputRaw(t *harnessTest, net *lntest.NetworkHarness,
// assertSignOutputRaw sends coins to a p2wkh address derived from the given // assertSignOutputRaw sends coins to a p2wkh address derived from the given
// target public key and then tries to spend that output again by invoking the // target public key and then tries to spend that output again by invoking the
// SignOutputRaw RPC with the key descriptor provided. // SignOutputRaw RPC with the key descriptor provided.
func assertSignOutputRaw(t *harnessTest, net *lntest.NetworkHarness, func assertSignOutputRaw(ht *lntemp.HarnessTest,
alice *lntest.HarnessNode, targetPubKey *btcec.PublicKey, alice *node.HarnessNode, targetPubKey *btcec.PublicKey,
keyDesc *signrpc.KeyDescriptor) { keyDesc *signrpc.KeyDescriptor) {
ctxb := context.Background()
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
pubKeyHash := btcutil.Hash160(targetPubKey.SerializeCompressed()) pubKeyHash := btcutil.Hash160(targetPubKey.SerializeCompressed())
targetAddr, err := btcutil.NewAddressWitnessPubKeyHash( targetAddr, err := btcutil.NewAddressWitnessPubKeyHash(
pubKeyHash, harnessNetParams, pubKeyHash, harnessNetParams,
) )
require.NoError(t.t, err) require.NoError(ht, err)
targetScript, err := txscript.PayToAddrScript(targetAddr) targetScript, err := txscript.PayToAddrScript(targetAddr)
require.NoError(t.t, err) require.NoError(ht, err)
// Send some coins to the generated p2wpkh address. // Send some coins to the generated p2wpkh address.
_, err = alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ req := &lnrpc.SendCoinsRequest{
Addr: targetAddr.String(), Addr: targetAddr.String(),
Amount: 800_000, Amount: 800_000,
}) }
require.NoError(t.t, err) alice.RPC.SendCoins(req)
// Wait until the TX is found in the mempool. // Wait until the TX is found in the mempool.
txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) txid := ht.Miner.AssertNumTxsInMempool(1)[0]
require.NoError(t.t, err)
targetOutputIndex := getOutputIndex( targetOutputIndex := ht.GetOutputIndex(txid, targetAddr.String())
t, net.Miner, txid, targetAddr.String(),
)
// Clear the mempool. // Clear the mempool.
mineBlocks(t, net, 1, 1) ht.MineBlocksAndAssertNumTxes(1, 1)
// Try to spend the output now to a new p2wkh address. // Try to spend the output now to a new p2wkh address.
p2wkhResp, err := alice.NewAddress(ctxt, &lnrpc.NewAddressRequest{ addrReq := &lnrpc.NewAddressRequest{Type: AddrTypeWitnessPubkeyHash}
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH, p2wkhResp := alice.RPC.NewAddress(addrReq)
})
require.NoError(t.t, err)
p2wkhAdrr, err := btcutil.DecodeAddress( p2wkhAdrr, err := btcutil.DecodeAddress(
p2wkhResp.Address, harnessNetParams, p2wkhResp.Address, harnessNetParams,
) )
require.NoError(t.t, err) require.NoError(ht, err)
p2wkhPkScript, err := txscript.PayToAddrScript(p2wkhAdrr) p2wkhPkScript, err := txscript.PayToAddrScript(p2wkhAdrr)
require.NoError(t.t, err) require.NoError(ht, err)
tx := wire.NewMsgTx(2) tx := wire.NewMsgTx(2)
tx.TxIn = []*wire.TxIn{{ tx.TxIn = []*wire.TxIn{{
@@ -339,24 +318,22 @@ func assertSignOutputRaw(t *harnessTest, net *lntest.NetworkHarness,
}} }}
var buf bytes.Buffer var buf bytes.Buffer
require.NoError(t.t, tx.Serialize(&buf)) require.NoError(ht, tx.Serialize(&buf))
signResp, err := alice.SignerClient.SignOutputRaw( signReq := &signrpc.SignReq{
ctxt, &signrpc.SignReq{ RawTxBytes: buf.Bytes(),
RawTxBytes: buf.Bytes(), SignDescs: []*signrpc.SignDescriptor{{
SignDescs: []*signrpc.SignDescriptor{{ Output: &signrpc.TxOut{
Output: &signrpc.TxOut{ PkScript: targetScript,
PkScript: targetScript, Value: 800_000,
Value: 800_000, },
}, InputIndex: 0,
InputIndex: 0, KeyDesc: keyDesc,
KeyDesc: keyDesc, Sighash: uint32(txscript.SigHashAll),
Sighash: uint32(txscript.SigHashAll), WitnessScript: targetScript,
WitnessScript: targetScript, }},
}}, }
}, signResp := alice.RPC.SignOutputRaw(signReq)
)
require.NoError(t.t, err)
tx.TxIn[0].Witness = wire.TxWitness{ tx.TxIn[0].Witness = wire.TxWitness{
append(signResp.RawSigs[0], byte(txscript.SigHashAll)), append(signResp.RawSigs[0], byte(txscript.SigHashAll)),
@@ -364,30 +341,25 @@ func assertSignOutputRaw(t *harnessTest, net *lntest.NetworkHarness,
} }
buf.Reset() buf.Reset()
require.NoError(t.t, tx.Serialize(&buf)) require.NoError(ht, tx.Serialize(&buf))
_, err = alice.WalletKitClient.PublishTransaction( alice.RPC.PublishTransaction(&walletrpc.Transaction{
ctxt, &walletrpc.Transaction{ TxHex: buf.Bytes(),
TxHex: buf.Bytes(), })
},
)
require.NoError(t.t, err)
// Wait until the spending tx is found. // Wait until the spending tx is found.
txid, err = waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) txid = ht.Miner.AssertNumTxsInMempool(1)[0]
require.NoError(t.t, err) p2wkhOutputIndex := ht.GetOutputIndex(txid, p2wkhAdrr.String())
p2wkhOutputIndex := getOutputIndex(
t, net.Miner, txid, p2wkhAdrr.String(),
)
op := &lnrpc.OutPoint{ op := &lnrpc.OutPoint{
TxidBytes: txid[:], TxidBytes: txid[:],
OutputIndex: uint32(p2wkhOutputIndex), OutputIndex: uint32(p2wkhOutputIndex),
} }
assertWalletUnspent(t, alice, op, "") ht.AssertUTXOInWallet(alice, op, "")
// Mine another block to clean up the mempool and to make sure the spend // Mine another block to clean up the mempool and to make sure the
// tx is actually included in a block. // spend tx is actually included in a block.
mineBlocks(t, net, 1, 1) ht.MineBlocksAndAssertNumTxes(1, 1)
} }
// deriveCustomizedKey uses the family and index to derive a public key from // deriveCustomizedKey uses the family and index to derive a public key from
-4
View File
@@ -4,10 +4,6 @@
package itest package itest
var allTestCases = []*testCase{ var allTestCases = []*testCase{
{
name: "sign output raw",
test: testSignOutputRaw,
},
{ {
name: "sign verify message", name: "sign verify message",
test: testSignVerifyMessage, test: testSignVerifyMessage,