lnd/lntest/itest/lnd_nonstd_sweep_test.go
eugene 6ec2826f6c
sweep: account for all script types in craftSweepTx
With this change, transactions created via craftSweepTx will be
standard. Previously, p2wsh/p2pkh scripts passed in via SendCoins would
be weighted as p2wpkh scripts. With a feerate of 1 sat/vbyte,
transactions returned would be non-standard. Luckily, the critical
sweeper subsystem only used p2wpkh scripts so this only affected
callers from the rpcserver.

Also added is an integration test that fails if SendCoins manages
to generate a non-standard transaction. All script types are now
accounted for in getWeightEstimate, which now errors if an unknown
script type is passed in.
2022-08-08 15:33:00 -04:00

148 lines
3.3 KiB
Go

package itest
import (
"context"
"testing"
"github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/stretchr/testify/require"
)
func testNonstdSweep(net *lntest.NetworkHarness, t *harnessTest) {
p2shAddr, err := btcutil.NewAddressScriptHash(
make([]byte, 1), harnessNetParams,
)
require.NoError(t.t, err)
p2pkhAddr, err := btcutil.NewAddressPubKeyHash(
make([]byte, 20), harnessNetParams,
)
require.NoError(t.t, err)
p2wshAddr, err := btcutil.NewAddressWitnessScriptHash(
make([]byte, 32), harnessNetParams,
)
require.NoError(t.t, err)
p2wkhAddr, err := btcutil.NewAddressWitnessPubKeyHash(
make([]byte, 20), harnessNetParams,
)
require.NoError(t.t, err)
p2trAddr, err := btcutil.NewAddressTaproot(
make([]byte, 32), harnessNetParams,
)
require.NoError(t.t, err)
tests := []struct {
name string
address string
}{
{
name: "p2sh SendCoins standardness",
address: p2shAddr.EncodeAddress(),
},
{
name: "p2pkh SendCoins standardness",
address: p2pkhAddr.EncodeAddress(),
},
{
name: "p2wsh SendCoins standardness",
address: p2wshAddr.EncodeAddress(),
},
{
name: "p2wkh SendCoins standardness",
address: p2wkhAddr.EncodeAddress(),
},
{
name: "p2tr SendCoins standardness",
address: p2trAddr.EncodeAddress(),
},
}
for _, test := range tests {
test := test
success := t.t.Run(test.name, func(t *testing.T) {
h := newHarnessTest(t, net)
testNonStdSweepInner(net, h, test.address)
})
if !success {
break
}
}
}
func testNonStdSweepInner(net *lntest.NetworkHarness, t *harnessTest,
address string) {
ctxb := context.Background()
carol := net.NewNode(t.t, "carol", nil)
// Give Carol a UTXO so SendCoins will behave as expected.
net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, carol)
// Set the fee estimate to 1sat/vbyte.
net.SetFeeEstimate(250)
// Make Carol call SendCoins with the SendAll flag and the created
// address.
sendReq := &lnrpc.SendCoinsRequest{
Addr: address,
SatPerVbyte: 1,
SendAll: true,
}
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
// If a non-standard transaction was created, then this SendCoins call
// will fail.
_, err := carol.SendCoins(ctxt, sendReq)
require.NoError(t.t, err)
// Fetch the txid so we can grab the raw transaction.
txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout)
require.NoError(t.t, err)
tx, err := net.Miner.Client.GetRawTransaction(txid)
require.NoError(t.t, err)
msgTx := tx.MsgTx()
// Fetch the fee of the transaction.
var (
inputVal int
outputVal int
fee int
)
for _, inp := range msgTx.TxIn {
// Fetch the previous outpoint's value.
prevOut := inp.PreviousOutPoint
ptx, err := net.Miner.Client.GetRawTransaction(&prevOut.Hash)
require.NoError(t.t, err)
pout := ptx.MsgTx().TxOut[prevOut.Index]
inputVal += int(pout.Value)
}
for _, outp := range msgTx.TxOut {
outputVal += int(outp.Value)
}
fee = inputVal - outputVal
// Fetch the vsize of the transaction so we can determine if the
// transaction pays >= 1 sat/vbyte.
rawTx, err := net.Miner.Client.GetRawTransactionVerbose(txid)
require.NoError(t.t, err)
// Require fee >= vbytes.
require.True(t.t, fee >= int(rawTx.Vsize))
}