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.
This commit is contained in:
eugene
2022-07-15 16:25:31 -04:00
parent 6060e05d7c
commit 6ec2826f6c
6 changed files with 311 additions and 15 deletions

View File

@@ -124,7 +124,6 @@ func createSweeperTestContext(t *testing.T) *sweeperTestContext {
timeoutChan: make(chan chan time.Time, 1),
}
var outputScriptCount byte
ctx.sweeper = New(&UtxoSweeperConfig{
Notifier: notifier,
Wallet: backend,
@@ -137,8 +136,8 @@ func createSweeperTestContext(t *testing.T) *sweeperTestContext {
Signer: &mock.DummySigner{},
GenSweepScript: func() ([]byte, error) {
script := make([]byte, input.P2WPKHSize)
script[0] = outputScriptCount
outputScriptCount++
script[0] = 0
script[1] = 20
return script, nil
},
FeeEstimator: estimator,
@@ -330,7 +329,8 @@ func assertTxSweepsInputs(t *testing.T, sweepTx *wire.MsgTx,
// NOTE: This assumes that transactions only have one output, as this is the
// only type of transaction the UtxoSweeper can create at the moment.
func assertTxFeeRate(t *testing.T, tx *wire.MsgTx,
expectedFeeRate chainfee.SatPerKWeight, inputs ...input.Input) {
expectedFeeRate chainfee.SatPerKWeight, changePk []byte,
inputs ...input.Input) {
t.Helper()
@@ -355,7 +355,9 @@ func assertTxFeeRate(t *testing.T, tx *wire.MsgTx,
outputAmt := tx.TxOut[0].Value
fee := btcutil.Amount(inputAmt - outputAmt)
_, estimator := getWeightEstimate(inputs, nil, 0, nil)
_, estimator, err := getWeightEstimate(inputs, nil, 0, changePk)
require.NoError(t, err)
txWeight := estimator.weight()
expectedFee := expectedFeeRate.FeeForWeight(int64(txWeight))
@@ -1092,14 +1094,19 @@ func TestDifferentFeePreferences(t *testing.T) {
// transactions to be broadcast in order of high to low fee preference.
ctx.tick()
// Generate the same type of sweep script that was used for weight
// estimation.
changePk, err := ctx.sweeper.cfg.GenSweepScript()
require.NoError(t, err)
// The first transaction broadcast should be the one spending the higher
// fee rate inputs.
sweepTx1 := ctx.receiveTx()
assertTxFeeRate(t, &sweepTx1, highFeeRate, input1, input2)
assertTxFeeRate(t, &sweepTx1, highFeeRate, changePk, input1, input2)
// The second should be the one spending the lower fee rate inputs.
sweepTx2 := ctx.receiveTx()
assertTxFeeRate(t, &sweepTx2, lowFeeRate, input3)
assertTxFeeRate(t, &sweepTx2, lowFeeRate, changePk, input3)
// With the transactions broadcast, we'll mine a block to so that the
// result is delivered to each respective client.
@@ -1218,10 +1225,15 @@ func TestBumpFeeRBF(t *testing.T) {
t.Fatal(err)
}
// Generate the same type of change script used so we can have accurate
// weight estimation.
changePk, err := ctx.sweeper.cfg.GenSweepScript()
require.NoError(t, err)
// Ensure that a transaction is broadcast with the lower fee preference.
ctx.tick()
lowFeeTx := ctx.receiveTx()
assertTxFeeRate(t, &lowFeeTx, lowFeeRate, &input)
assertTxFeeRate(t, &lowFeeTx, lowFeeRate, changePk, &input)
// We'll then attempt to bump its fee rate.
highFeePref := FeePreference{ConfTarget: 6}
@@ -1242,7 +1254,7 @@ func TestBumpFeeRBF(t *testing.T) {
// A higher fee rate transaction should be immediately broadcast.
ctx.tick()
highFeeTx := ctx.receiveTx()
assertTxFeeRate(t, &highFeeTx, highFeeRate, &input)
assertTxFeeRate(t, &highFeeTx, highFeeRate, changePk, &input)
// We'll finish our test by mining the sweep transaction.
ctx.backend.mine()