lnwallet: reject funding flows if local amount is insufficient w.r.t fees
This commit is contained in:
parent
c986e52da7
commit
24ad3e17de
@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -501,9 +502,12 @@ func testCancelNonExistantReservation(miner *rpctest.Harness,
|
||||
}
|
||||
|
||||
// Create our own reservation, give it some ID.
|
||||
res := lnwallet.NewChannelReservation(
|
||||
res, err := lnwallet.NewChannelReservation(
|
||||
1000, 1000, feeRate, alice, 22, 10, &testHdSeed,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create res: %v", err)
|
||||
}
|
||||
|
||||
// Attempt to cancel this reservation. This should fail, we know
|
||||
// nothing of it.
|
||||
@ -512,6 +516,28 @@ func testCancelNonExistantReservation(miner *rpctest.Harness,
|
||||
}
|
||||
}
|
||||
|
||||
func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
|
||||
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
||||
|
||||
// We'll attempt to create a new reservation with an extremely high fee
|
||||
// rate. This should push our balance into the negative and result in a
|
||||
// failure to create the reservation.
|
||||
fundingAmount := btcutil.Amount(4 * 1e8)
|
||||
feePerKw := btcutil.Amount(btcutil.SatoshiPerBitcoin * 10)
|
||||
_, err := alice.InitChannelReservation(
|
||||
fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub,
|
||||
bobAddr, chainHash,
|
||||
)
|
||||
switch {
|
||||
case err == nil:
|
||||
t.Fatalf("initialization should've failed due to " +
|
||||
"insufficient local amount")
|
||||
|
||||
case !strings.Contains(err.Error(), "local output is too small"):
|
||||
t.Fatalf("incorrect error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func assertContributionInitPopulated(t *testing.T, c *lnwallet.ChannelContribution) {
|
||||
_, _, line, _ := runtime.Caller(1)
|
||||
|
||||
@ -1276,6 +1302,10 @@ type walletTestCase struct {
|
||||
}
|
||||
|
||||
var walletTests = []walletTestCase{
|
||||
{
|
||||
name: "insane fee reject",
|
||||
test: testReservationInitiatorBalanceBelowDustCancel,
|
||||
},
|
||||
{
|
||||
name: "single funding workflow",
|
||||
test: testSingleFunderReservationWorkflow,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
@ -136,7 +137,7 @@ type ChannelReservation struct {
|
||||
// lnwallet.InitChannelReservation interface.
|
||||
func NewChannelReservation(capacity, fundingAmt, commitFeePerKw btcutil.Amount,
|
||||
wallet *LightningWallet, id uint64, pushMSat lnwire.MilliSatoshi,
|
||||
chainHash *chainhash.Hash) *ChannelReservation {
|
||||
chainHash *chainhash.Hash) (*ChannelReservation, error) {
|
||||
|
||||
var (
|
||||
ourBalance lnwire.MilliSatoshi
|
||||
@ -181,6 +182,17 @@ func NewChannelReservation(capacity, fundingAmt, commitFeePerKw btcutil.Amount,
|
||||
initiator = true
|
||||
}
|
||||
|
||||
// If we're the initiator and our starting balance within the channel
|
||||
// after we take account of fees is below dust, then we'll reject this
|
||||
// channel creation request.
|
||||
//
|
||||
// TODO(roasbeef): reject if 30% goes to fees? dust channel
|
||||
if initiator && ourBalance.ToSatoshis() <= DefaultDustLimit() {
|
||||
return nil, fmt.Errorf("unable to init reservation, with "+
|
||||
"fee=%v sat/kw, local output is too small: %v sat",
|
||||
int64(commitFee), int64(ourBalance.ToSatoshis()))
|
||||
}
|
||||
|
||||
// Next we'll set the channel type based on what we can ascertain about
|
||||
// the balances/push amount within the channel.
|
||||
var chanType channeldb.ChannelType
|
||||
@ -231,7 +243,7 @@ func NewChannelReservation(capacity, fundingAmt, commitFeePerKw btcutil.Amount,
|
||||
chanOpen: make(chan *openChanDetails, 1),
|
||||
chanOpenErr: make(chan error, 1),
|
||||
wallet: wallet,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetNumConfsRequired sets the number of confirmations that are required for
|
||||
|
@ -492,8 +492,13 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
|
||||
}
|
||||
|
||||
id := atomic.AddUint64(&l.nextFundingID, 1)
|
||||
reservation := NewChannelReservation(req.capacity, req.fundingAmount,
|
||||
reservation, err := NewChannelReservation(req.capacity, req.fundingAmount,
|
||||
req.commitFeePerKw, l, id, req.pushMSat, l.Cfg.NetParams.GenesisHash)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.resp <- nil
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the mutex on the ChannelReservation to ensure thread-safety
|
||||
reservation.Lock()
|
||||
@ -523,7 +528,6 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
|
||||
// for the duration of the channel. The keys include: our multi-sig
|
||||
// key, the base revocation key, the base htlc key,the base payment
|
||||
// key, and the delayed payment key.
|
||||
var err error
|
||||
reservation.ourContribution.MultiSigKey, err = l.NewRawKey()
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
|
Loading…
Reference in New Issue
Block a user