Merge pull request #4546 from bjarnemagnussen/fix-coinselect-tests
chanfunding: Add/improve tests for CoinSelectSubtractFees
This commit is contained in:
commit
1c96cc7e10
@ -208,7 +208,7 @@ func CoinSelectSubtractFees(feeRate chainfee.SatPerKWeight, amt,
|
|||||||
// TODO(halseth): smarter fee limit. Make configurable or dynamic wrt
|
// TODO(halseth): smarter fee limit. Make configurable or dynamic wrt
|
||||||
// total funding size?
|
// total funding size?
|
||||||
if fee > totalOut/5 {
|
if fee > totalOut/5 {
|
||||||
return nil, 0, 0, fmt.Errorf("fee %v on total output"+
|
return nil, 0, 0, fmt.Errorf("fee %v on total output "+
|
||||||
"value %v", fee, totalOut)
|
"value %v", fee, totalOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package chanfunding
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
@ -205,18 +206,26 @@ func TestCoinSelectSubtractFees(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
const feeRate = chainfee.SatPerKWeight(100)
|
const feeRate = chainfee.SatPerKWeight(100)
|
||||||
|
const highFeeRate = chainfee.SatPerKWeight(1000)
|
||||||
const dustLimit = btcutil.Amount(1000)
|
const dustLimit = btcutil.Amount(1000)
|
||||||
const dust = btcutil.Amount(100)
|
const dust = btcutil.Amount(100)
|
||||||
|
|
||||||
|
// removeAmounts replaces any amounts in string with "<amt>".
|
||||||
|
removeAmounts := func(s string) string {
|
||||||
|
re := regexp.MustCompile(`[[:digit:]]+\.?[[:digit:]]*`)
|
||||||
|
return re.ReplaceAllString(s, "<amt>")
|
||||||
|
}
|
||||||
|
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
name string
|
name string
|
||||||
|
highFee bool
|
||||||
spendValue btcutil.Amount
|
spendValue btcutil.Amount
|
||||||
coins []Coin
|
coins []Coin
|
||||||
|
|
||||||
expectedInput []btcutil.Amount
|
expectedInput []btcutil.Amount
|
||||||
expectedFundingAmt btcutil.Amount
|
expectedFundingAmt btcutil.Amount
|
||||||
expectedChange btcutil.Amount
|
expectedChange btcutil.Amount
|
||||||
expectErr bool
|
expectErr string
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []testCase{
|
testCases := []testCase{
|
||||||
@ -242,6 +251,27 @@ func TestCoinSelectSubtractFees(t *testing.T) {
|
|||||||
expectedFundingAmt: 1*btcutil.SatoshiPerBitcoin - fundingFee(feeRate, 1, false),
|
expectedFundingAmt: 1*btcutil.SatoshiPerBitcoin - fundingFee(feeRate, 1, false),
|
||||||
expectedChange: 0,
|
expectedChange: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// We have 1.0 BTC available and spend half of it. This
|
||||||
|
// should lead to a funding TX with a change output.
|
||||||
|
name: "spend with change",
|
||||||
|
coins: []Coin{
|
||||||
|
{
|
||||||
|
TxOut: wire.TxOut{
|
||||||
|
PkScript: p2wkhScript,
|
||||||
|
Value: 1 * btcutil.SatoshiPerBitcoin,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spendValue: 0.5 * btcutil.SatoshiPerBitcoin,
|
||||||
|
|
||||||
|
// The one and only input will be selected.
|
||||||
|
expectedInput: []btcutil.Amount{
|
||||||
|
1 * btcutil.SatoshiPerBitcoin,
|
||||||
|
},
|
||||||
|
expectedFundingAmt: 0.5*btcutil.SatoshiPerBitcoin - fundingFee(feeRate, 1, true),
|
||||||
|
expectedChange: 0.5 * btcutil.SatoshiPerBitcoin,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// The total funds available is below the dust limit
|
// The total funds available is below the dust limit
|
||||||
// after paying fees.
|
// after paying fees.
|
||||||
@ -250,13 +280,14 @@ func TestCoinSelectSubtractFees(t *testing.T) {
|
|||||||
{
|
{
|
||||||
TxOut: wire.TxOut{
|
TxOut: wire.TxOut{
|
||||||
PkScript: p2wkhScript,
|
PkScript: p2wkhScript,
|
||||||
Value: int64(fundingFee(feeRate, 1, false) + dust),
|
Value: int64(fundingFee(feeRate, 1, false) + dustLimit),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
spendValue: fundingFee(feeRate, 1, false) + dust,
|
spendValue: fundingFee(feeRate, 1, false) + dust,
|
||||||
|
|
||||||
expectErr: true,
|
expectErr: "output amount(<amt> BTC) after subtracting " +
|
||||||
|
"fees(<amt> BTC) below dust limit(<amt> BTC)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// After subtracting fees, the resulting change output
|
// After subtracting fees, the resulting change output
|
||||||
@ -320,18 +351,19 @@ func TestCoinSelectSubtractFees(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If more than 20% of funds goes to fees, it should fail.
|
// If more than 20% of funds goes to fees, it should fail.
|
||||||
name: "high fee",
|
name: "high fee",
|
||||||
|
highFee: true,
|
||||||
coins: []Coin{
|
coins: []Coin{
|
||||||
{
|
{
|
||||||
TxOut: wire.TxOut{
|
TxOut: wire.TxOut{
|
||||||
PkScript: p2wkhScript,
|
PkScript: p2wkhScript,
|
||||||
Value: int64(5 * fundingFee(feeRate, 1, false)),
|
Value: int64(5 * fundingFee(highFeeRate, 1, false)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
spendValue: 5 * fundingFee(feeRate, 1, false),
|
spendValue: 5 * fundingFee(highFeeRate, 1, false),
|
||||||
|
|
||||||
expectErr: true,
|
expectErr: "fee <amt> BTC on total output value <amt> BTC",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,22 +371,36 @@ func TestCoinSelectSubtractFees(t *testing.T) {
|
|||||||
test := test
|
test := test
|
||||||
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
feeRate := feeRate
|
||||||
|
if test.highFee {
|
||||||
|
feeRate = highFeeRate
|
||||||
|
}
|
||||||
|
|
||||||
selected, localFundingAmt, changeAmt, err := CoinSelectSubtractFees(
|
selected, localFundingAmt, changeAmt, err := CoinSelectSubtractFees(
|
||||||
feeRate, test.spendValue, dustLimit, test.coins,
|
feeRate, test.spendValue, dustLimit, test.coins,
|
||||||
)
|
)
|
||||||
if !test.expectErr && err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
switch {
|
||||||
|
case test.expectErr == "":
|
||||||
|
t.Fatalf(err.Error())
|
||||||
|
|
||||||
|
case test.expectErr != removeAmounts(err.Error()):
|
||||||
|
t.Fatalf("expected error '%v', got '%v'",
|
||||||
|
test.expectErr,
|
||||||
|
removeAmounts(err.Error()))
|
||||||
|
|
||||||
|
// If we got an expected error, there is
|
||||||
|
// nothing more to test.
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.expectErr && err == nil {
|
// Check that there was no expected error we missed.
|
||||||
|
if test.expectErr != "" {
|
||||||
t.Fatalf("expected error")
|
t.Fatalf("expected error")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we got an expected error, there is nothing more to test.
|
|
||||||
if test.expectErr {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the selected inputs match what we expect.
|
// Check that the selected inputs match what we expect.
|
||||||
if len(selected) != len(test.expectedInput) {
|
if len(selected) != len(test.expectedInput) {
|
||||||
t.Fatalf("expected %v inputs, got %v",
|
t.Fatalf("expected %v inputs, got %v",
|
||||||
|
Loading…
Reference in New Issue
Block a user