lnwallet: replace hard-coded fees and adjust tests accordingly

This commit replaces the hard-coded 5000 satoshi fees with calls to the
FeeEstimator interface. This should provide a way to cleanly plug in
additional fee calculation algorithms in the future. This change
affected quite a few tests. When possible, the tests were changed to
assert amounts sent rather than balances so that fees wouldn't need to
be taken into account. There were several tests for which this wasn't
possible, so calls to the static fee calculator were made.
This commit is contained in:
bryanvu 2017-05-01 11:45:02 -07:00 committed by Olaoluwa Osuntokun
parent abe2e502d5
commit 4ac7cc719f
8 changed files with 222 additions and 242 deletions

@ -283,6 +283,20 @@ func assertNumConnections(ctxt context.Context, t *harnessTest,
} }
} }
// calcStaticFee calculates appropriate fees for commitment transactions. This
// function provides a simple way to allow test balance assertions to take fee
// calculations into account.
// TODO(bvu): Refactor when dynamic fee estimation is added.
func calcStaticFee(numHTLCs int) btcutil.Amount {
const (
commitWeight = btcutil.Amount(724)
htlcWeight = 172
feePerByte = btcutil.Amount(250 * 4)
)
return feePerByte * (commitWeight +
btcutil.Amount(htlcWeight*numHTLCs)) / 1000
}
// testBasicChannelFunding performs a test exercising expected behavior from a // testBasicChannelFunding performs a test exercising expected behavior from a
// basic funding workflow. The test creates a new channel between Alice and // basic funding workflow. The test creates a new channel between Alice and
// Bob, then immediately closes the channel after asserting some expected post // Bob, then immediately closes the channel after asserting some expected post
@ -322,9 +336,9 @@ func testBasicChannelFunding(net *networkHarness, t *harnessTest) {
if err != nil { if err != nil {
t.Fatalf("unable to get bobs's balance: %v", err) t.Fatalf("unable to get bobs's balance: %v", err)
} }
if aliceBal.Balance != int64(chanAmt-pushAmt) { if aliceBal.Balance != int64(chanAmt-pushAmt-calcStaticFee(0)) {
t.Fatalf("alice's balance is incorrect: expected %v got %v", t.Fatalf("alice's balance is incorrect: expected %v got %v",
chanAmt-pushAmt, aliceBal) chanAmt-pushAmt-calcStaticFee(0), aliceBal)
} }
if bobBal.Balance != int64(pushAmt) { if bobBal.Balance != int64(pushAmt) {
t.Fatalf("bob's balance is incorrect: expected %v got %v", t.Fatalf("bob's balance is incorrect: expected %v got %v",
@ -631,7 +645,7 @@ func testChannelBalance(net *networkHarness, t *harnessTest) {
// As this is a single funder channel, Alice's balance should be // As this is a single funder channel, Alice's balance should be
// exactly 0.5 BTC since now state transitions have taken place yet. // exactly 0.5 BTC since now state transitions have taken place yet.
checkChannelBalance(net.Alice, amount) checkChannelBalance(net.Alice, amount-calcStaticFee(0))
// Ensure Bob currently has no available balance within the channel. // Ensure Bob currently has no available balance within the channel.
checkChannelBalance(net.Bob, 0) checkChannelBalance(net.Bob, 0)
@ -1864,6 +1878,7 @@ func testHtlcErrorPropagation(net *networkHarness, t *harnessTest) {
t.Fatalf("channel not seen by alice before timeout: %v", err) t.Fatalf("channel not seen by alice before timeout: %v", err)
} }
commitFee := calcStaticFee(0)
assertBaseBalance := func() { assertBaseBalance := func() {
balReq := &lnrpc.ChannelBalanceRequest{} balReq := &lnrpc.ChannelBalanceRequest{}
aliceBal, err := net.Alice.ChannelBalance(ctxb, balReq) aliceBal, err := net.Alice.ChannelBalance(ctxb, balReq)
@ -1874,13 +1889,13 @@ func testHtlcErrorPropagation(net *networkHarness, t *harnessTest) {
if err != nil { if err != nil {
t.Fatalf("unable to get channel balance: %v", err) t.Fatalf("unable to get channel balance: %v", err)
} }
if aliceBal.Balance != int64(chanAmt) { if aliceBal.Balance != int64(chanAmt-commitFee) {
t.Fatalf("alice has an incorrect balance: expected %v got %v", t.Fatalf("alice has an incorrect balance: expected %v got %v",
int64(chanAmt), aliceBal) int64(chanAmt-commitFee), aliceBal)
} }
if bobBal.Balance != int64(chanAmt) { if bobBal.Balance != int64(chanAmt-commitFee) {
t.Fatalf("bob has an incorrect balance: expected %v got %v", t.Fatalf("bob has an incorrect balance: expected %v got %v",
int64(chanAmt), bobBal) int64(chanAmt-commitFee), bobBal)
} }
} }

@ -683,8 +683,7 @@ type LightningChannel struct {
// automatically persist pertinent state to the database in an efficient // automatically persist pertinent state to the database in an efficient
// manner. // manner.
func NewLightningChannel(signer Signer, events chainntnfs.ChainNotifier, func NewLightningChannel(signer Signer, events chainntnfs.ChainNotifier,
fe FeeEstimator, state *channeldb.OpenChannel) (*LightningChannel, fe FeeEstimator, state *channeldb.OpenChannel) (*LightningChannel, error) {
error) {
lc := &LightningChannel{ lc := &LightningChannel{
signer: signer, signer: signer,
@ -719,6 +718,7 @@ func NewLightningChannel(signer Signer, events chainntnfs.ChainNotifier,
ourMessageIndex: 0, ourMessageIndex: 0,
theirBalance: state.TheirBalance, theirBalance: state.TheirBalance,
theirMessageIndex: 0, theirMessageIndex: 0,
fee: state.CommitFee,
}) })
walletLog.Debugf("ChannelPoint(%v), starting local commitment: %v", walletLog.Debugf("ChannelPoint(%v), starting local commitment: %v",
state.ChanID, newLogClosure(func() string { state.ChanID, newLogClosure(func() string {
@ -739,6 +739,7 @@ func NewLightningChannel(signer Signer, events chainntnfs.ChainNotifier,
ourMessageIndex: 0, ourMessageIndex: 0,
theirBalance: state.TheirBalance, theirBalance: state.TheirBalance,
theirMessageIndex: 0, theirMessageIndex: 0,
fee: state.CommitFee,
} }
if logTail == nil { if logTail == nil {
remoteCommitment.height = 0 remoteCommitment.height = 0
@ -1193,8 +1194,6 @@ func (lc *LightningChannel) restoreStateLogs() error {
lc.localCommitChain.tail().theirMessageIndex = theirCounter lc.localCommitChain.tail().theirMessageIndex = theirCounter
lc.remoteCommitChain.tail().ourMessageIndex = ourCounter lc.remoteCommitChain.tail().ourMessageIndex = ourCounter
lc.remoteCommitChain.tail().theirMessageIndex = theirCounter lc.remoteCommitChain.tail().theirMessageIndex = theirCounter
lc.localCommitChain.tail().fee = lc.channelState.CommitFee
lc.remoteCommitChain.tail().fee = lc.channelState.CommitFee
return nil return nil
} }
@ -1262,6 +1261,10 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
ourBalance = commitChain.tip().ourBalance ourBalance = commitChain.tip().ourBalance
theirBalance = commitChain.tip().theirBalance theirBalance = commitChain.tip().theirBalance
// Add the fee from the previous commitment state back to the
// initiator's balance, so that the fee can be recalculated and
// re-applied in case fee estimation parameters have changed or the
// number of outstanding HTLCs has changed.
if lc.channelState.IsInitiator { if lc.channelState.IsInitiator {
ourBalance = ourBalance + commitChain.tip().fee ourBalance = ourBalance + commitChain.tip().fee
} else if !lc.channelState.IsInitiator { } else if !lc.channelState.IsInitiator {
@ -1278,24 +1281,54 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
filteredHTLCView := lc.evaluateHTLCView(htlcView, &ourBalance, &theirBalance, filteredHTLCView := lc.evaluateHTLCView(htlcView, &ourBalance, &theirBalance,
nextHeight, remoteChain) nextHeight, remoteChain)
// Determine how many current HTLCs are over the dust limit, and should
// be counted for the purpose of fee calculation.
var dustLimit btcutil.Amount
if remoteChain {
dustLimit = lc.channelState.TheirDustLimit
} else {
dustLimit = lc.channelState.OurDustLimit
}
numHTLCs := 0
for _, htlc := range filteredHTLCView.ourUpdates {
if htlc.Amount < dustLimit {
continue
}
numHTLCs++
}
for _, htlc := range filteredHTLCView.theirUpdates {
if htlc.Amount < dustLimit {
continue
}
numHTLCs++
}
// Calculate the fee for the commitment transaction based on its size.
commitFee := btcutil.Amount(lc.feeEstimator.EstimateFeePerWeight(1)) *
(commitWeight + btcutil.Amount(htlcWeight*numHTLCs)) / 1000
if lc.channelState.IsInitiator {
ourBalance = ourBalance - commitFee
} else if !lc.channelState.IsInitiator {
theirBalance = theirBalance - commitFee
}
var selfKey *btcec.PublicKey var selfKey *btcec.PublicKey
var remoteKey *btcec.PublicKey var remoteKey *btcec.PublicKey
var delay uint32 var delay uint32
var delayBalance, p2wkhBalance, dustLimit btcutil.Amount var delayBalance, p2wkhBalance btcutil.Amount
if remoteChain { if remoteChain {
selfKey = lc.channelState.TheirCommitKey selfKey = lc.channelState.TheirCommitKey
remoteKey = lc.channelState.OurCommitKey remoteKey = lc.channelState.OurCommitKey
delay = lc.channelState.RemoteCsvDelay delay = lc.channelState.RemoteCsvDelay
delayBalance = theirBalance delayBalance = theirBalance
p2wkhBalance = ourBalance p2wkhBalance = ourBalance
dustLimit = lc.channelState.TheirDustLimit
} else { } else {
selfKey = lc.channelState.OurCommitKey selfKey = lc.channelState.OurCommitKey
remoteKey = lc.channelState.TheirCommitKey remoteKey = lc.channelState.TheirCommitKey
delay = lc.channelState.LocalCsvDelay delay = lc.channelState.LocalCsvDelay
delayBalance = ourBalance delayBalance = ourBalance
p2wkhBalance = theirBalance p2wkhBalance = theirBalance
dustLimit = lc.channelState.OurDustLimit
} }
// Generate a new commitment transaction with all the latest // Generate a new commitment transaction with all the latest
@ -1352,6 +1385,7 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
ourMessageIndex: ourLogIndex, ourMessageIndex: ourLogIndex,
theirMessageIndex: theirLogIndex, theirMessageIndex: theirLogIndex,
theirBalance: theirBalance, theirBalance: theirBalance,
fee: commitFee,
} }
// In order to ensure _none_ of the HTLC's associated with this new // In order to ensure _none_ of the HTLC's associated with this new
@ -2502,6 +2536,17 @@ func (lc *LightningChannel) InitCooperativeClose() ([]byte, *chainhash.Hash, err
return nil, nil, ErrChanClosing return nil, nil, ErrChanClosing
} }
// Calculate the fee for the commitment transaction based on its size.
// For a cooperative close, there should be no HTLCs.
commitFee := btcutil.Amount(lc.feeEstimator.EstimateFeePerWeight(1)) *
commitWeight / 1000
if lc.channelState.IsInitiator {
lc.channelState.OurBalance = lc.channelState.OurBalance - commitFee
} else {
lc.channelState.TheirBalance = lc.channelState.TheirBalance - commitFee
}
closeTx := CreateCooperativeCloseTx(lc.fundingTxIn, closeTx := CreateCooperativeCloseTx(lc.fundingTxIn,
lc.channelState.OurDustLimit, lc.channelState.TheirDustLimit, lc.channelState.OurDustLimit, lc.channelState.TheirDustLimit,
lc.channelState.OurBalance, lc.channelState.TheirBalance, lc.channelState.OurBalance, lc.channelState.TheirBalance,
@ -2552,6 +2597,17 @@ func (lc *LightningChannel) CompleteCooperativeClose(remoteSig []byte) (*wire.Ms
return nil, ErrChanClosing return nil, ErrChanClosing
} }
// Calculate the fee for the commitment transaction based on its size.
// For a cooperative close, there should be no HTLCs.
commitFee := btcutil.Amount(lc.feeEstimator.EstimateFeePerWeight(1)) *
commitWeight / 1000
if lc.channelState.IsInitiator {
lc.channelState.OurBalance = lc.channelState.OurBalance - commitFee
} else {
lc.channelState.TheirBalance = lc.channelState.TheirBalance - commitFee
}
// Create the transaction used to return the current settled balance // Create the transaction used to return the current settled balance
// on this active channel back to both parties. In this current model, // on this active channel back to both parties. In this current model,
// the initiator pays full fees for the cooperative close transaction. // the initiator pays full fees for the cooperative close transaction.
@ -2695,15 +2751,6 @@ func CreateCooperativeCloseTx(fundingTxIn *wire.TxIn,
closeTx := wire.NewMsgTx(2) closeTx := wire.NewMsgTx(2)
closeTx.AddTxIn(fundingTxIn) closeTx.AddTxIn(fundingTxIn)
// The initiator of a cooperative closure pays the fee in entirety.
// Determine if we're the initiator so we can compute fees properly.
if initiator {
// TODO(roasbeef): take sat/byte here instead of properly calc
ourBalance -= 5000
} else {
theirBalance -= 5000
}
// Create both cooperative closure outputs, properly respecting the // Create both cooperative closure outputs, properly respecting the
// dust limits of both parties. // dust limits of both parties.
if ourBalance >= localDust { if ourBalance >= localDust {

@ -329,6 +329,20 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
return channelAlice, channelBob, cleanUpFunc, nil return channelAlice, channelBob, cleanUpFunc, nil
} }
// calcStaticFee calculates appropriate fees for commitment transactions. This
// function provides a simple way to allow test balance assertions to take fee
// calculations into account.
// TODO(bvu): Refactor when dynamic fee estimation is added.
func calcStaticFee(numHTLCs int) btcutil.Amount {
const (
commitWeight = btcutil.Amount(724)
htlcWeight = 172
feePerByte = btcutil.Amount(50 * 4)
)
return feePerByte * (commitWeight +
btcutil.Amount(htlcWeight*numHTLCs)) / 1000
}
// TestSimpleAddSettleWorkflow tests a simple channel scenario wherein the // TestSimpleAddSettleWorkflow tests a simple channel scenario wherein the
// local node (Alice in this case) creates a new outgoing HTLC to bob, commits // local node (Alice in this case) creates a new outgoing HTLC to bob, commits
// this change, then bob immediately commits a settlement of the HTLC after the // this change, then bob immediately commits a settlement of the HTLC after the
@ -429,25 +443,27 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
"forward %v", len(htlcs)) "forward %v", len(htlcs))
} }
// At this point, both sides should have the proper balance, and // At this point, both sides should have the proper number of satoshis
// commitment height updated within their local channel state. // sent, and commitment height updated within their local channel
aliceBalance := btcutil.Amount(4 * 1e8) // state.
bobBalance := btcutil.Amount(5 * 1e8) aliceSent := uint64(0)
if aliceChannel.channelState.OurBalance != aliceBalance { bobSent := uint64(0)
t.Fatalf("alice has incorrect local balance %v vs %v",
aliceChannel.channelState.OurBalance, aliceBalance) if aliceChannel.channelState.TotalSatoshisSent != aliceSent {
t.Fatalf("alice has incorrect satoshis sent: %v vs %v",
aliceChannel.channelState.TotalSatoshisSent, aliceSent)
} }
if aliceChannel.channelState.TheirBalance != bobBalance { if aliceChannel.channelState.TotalSatoshisReceived != bobSent {
t.Fatalf("alice has incorrect remote balance %v vs %v", t.Fatalf("alice has incorrect satoshis received %v vs %v",
aliceChannel.channelState.TheirBalance, bobBalance) aliceChannel.channelState.TotalSatoshisReceived, bobSent)
} }
if bobChannel.channelState.OurBalance != bobBalance { if bobChannel.channelState.TotalSatoshisSent != bobSent {
t.Fatalf("bob has incorrect local balance %v vs %v", t.Fatalf("bob has incorrect satoshis sent %v vs %v",
bobChannel.channelState.OurBalance, bobBalance) bobChannel.channelState.TotalSatoshisSent, bobSent)
} }
if bobChannel.channelState.TheirBalance != aliceBalance { if bobChannel.channelState.TotalSatoshisReceived != aliceSent {
t.Fatalf("bob has incorrect remote balance %v vs %v", t.Fatalf("bob has incorrect satoshis received %v vs %v",
bobChannel.channelState.TheirBalance, aliceBalance) bobChannel.channelState.TotalSatoshisReceived, aliceSent)
} }
if bobChannel.currentHeight != 1 { if bobChannel.currentHeight != 1 {
t.Fatalf("bob has incorrect commitment height, %v vs %v", t.Fatalf("bob has incorrect commitment height, %v vs %v",
@ -526,25 +542,7 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
// 4 BTC. Alice's channel should show 1 BTC sent and Bob's channel should // 4 BTC. Alice's channel should show 1 BTC sent and Bob's channel should
// show 1 BTC received. They should also be at commitment height two, // show 1 BTC received. They should also be at commitment height two,
// with the revocation window extended by by 1 (5). // with the revocation window extended by by 1 (5).
aliceSettleBalance := btcutil.Amount(4 * 1e8)
bobSettleBalance := btcutil.Amount(6 * 1e8)
satoshisTransferred := uint64(100000000) satoshisTransferred := uint64(100000000)
if aliceChannel.channelState.OurBalance != aliceSettleBalance {
t.Fatalf("alice has incorrect local balance %v vs %v",
aliceChannel.channelState.OurBalance, aliceSettleBalance)
}
if aliceChannel.channelState.TheirBalance != bobSettleBalance {
t.Fatalf("alice has incorrect remote balance %v vs %v",
aliceChannel.channelState.TheirBalance, bobSettleBalance)
}
if bobChannel.channelState.OurBalance != bobSettleBalance {
t.Fatalf("bob has incorrect local balance %v vs %v",
bobChannel.channelState.OurBalance, bobSettleBalance)
}
if bobChannel.channelState.TheirBalance != aliceSettleBalance {
t.Fatalf("bob has incorrect remote balance %v vs %v",
bobChannel.channelState.TheirBalance, aliceSettleBalance)
}
if aliceChannel.channelState.TotalSatoshisSent != satoshisTransferred { if aliceChannel.channelState.TotalSatoshisSent != satoshisTransferred {
t.Fatalf("alice satoshis sent incorrect %v vs %v expected", t.Fatalf("alice satoshis sent incorrect %v vs %v expected",
aliceChannel.channelState.TotalSatoshisSent, aliceChannel.channelState.TotalSatoshisSent,
@ -1060,6 +1058,42 @@ func TestCheckDustLimit(t *testing.T) {
} }
defer cleanUp() defer cleanUp()
assertChannelState := func(chanA, chanB *LightningChannel, numOutsA,
numOutsB int, amountSentA, amountSentB uint64) {
commitment := chanA.localCommitChain.tip()
if len(commitment.txn.TxOut) != numOutsA {
t.Fatalf("incorrect # of outputs: expected %v, got %v",
numOutsA, len(commitment.txn.TxOut))
}
commitment = chanB.localCommitChain.tip()
if len(commitment.txn.TxOut) != numOutsB {
t.Fatalf("Incorrect # of outputs: expected %v, got %v",
numOutsB, len(commitment.txn.TxOut))
}
if chanA.channelState.TotalSatoshisSent != amountSentA {
t.Fatalf("alice satoshis sent incorrect: expected %v, "+
"got %v", amountSentA,
chanA.channelState.TotalSatoshisSent)
}
if chanA.channelState.TotalSatoshisReceived != amountSentB {
t.Fatalf("alice satoshis received incorrect: expected"+
"%v, got %v", amountSentB,
chanA.channelState.TotalSatoshisReceived)
}
if chanB.channelState.TotalSatoshisSent != amountSentB {
t.Fatalf("bob satoshis sent incorrect: expected %v, "+
" got %v", amountSentB,
chanB.channelState.TotalSatoshisSent)
}
if chanB.channelState.TotalSatoshisReceived != amountSentA {
t.Fatalf("bob satoshis received incorrect: expected "+
"%v, got %v", amountSentA,
chanB.channelState.TotalSatoshisReceived)
}
}
aliceDustLimit := aliceChannel.channelState.OurDustLimit aliceDustLimit := aliceChannel.channelState.OurDustLimit
bobDustLimit := bobChannel.channelState.OurDustLimit bobDustLimit := bobChannel.channelState.OurDustLimit
htlcAmount := btcutil.Amount(500) htlcAmount := btcutil.Amount(500)
@ -1070,9 +1104,6 @@ func TestCheckDustLimit(t *testing.T) {
bobDustLimit) bobDustLimit)
} }
aliceAmount := aliceChannel.channelState.OurBalance
bobAmount := bobChannel.channelState.OurBalance
htlc, preimage := createHTLC(0, htlcAmount) htlc, preimage := createHTLC(0, htlcAmount)
if _, err := aliceChannel.AddHTLC(htlc); err != nil { if _, err := aliceChannel.AddHTLC(htlc); err != nil {
t.Fatalf("alice unable to add htlc: %v", err) t.Fatalf("alice unable to add htlc: %v", err)
@ -1090,34 +1121,8 @@ func TestCheckDustLimit(t *testing.T) {
// will be settled. // will be settled.
// From Alice point of view HTLC's amount is bigger than dust limit. // From Alice point of view HTLC's amount is bigger than dust limit.
commitment := aliceChannel.localCommitChain.tip()
if len(commitment.txn.TxOut) != 3 {
t.Fatalf("incorrect number of outputs: expected %v, got %v",
3, len(commitment.txn.TxOut))
}
if commitment.ourBalance != aliceAmount-htlcAmount {
t.Fatalf("Alice has wrong balance: expected %v, got %v",
aliceAmount-htlcAmount, commitment.ourBalance)
}
if commitment.theirBalance != bobAmount {
t.Fatalf("Alice has wrong balance for Bob: expected %v, got %v",
bobAmount, commitment.theirBalance)
}
// From Bob point of view HTLC's amount is lower then dust limit. // From Bob point of view HTLC's amount is lower then dust limit.
commitment = bobChannel.localCommitChain.tip() assertChannelState(aliceChannel, bobChannel, 3, 2, 0, 0)
if len(commitment.txn.TxOut) != 2 {
t.Fatalf("Incorrect number of outputs: expected %v, got %v",
2, len(commitment.txn.TxOut))
}
if commitment.theirBalance != aliceAmount-htlcAmount {
t.Fatalf("Bob has wrong balance for Alice: expected %v, got %v",
aliceAmount-htlcAmount, commitment.theirBalance)
}
if commitment.ourBalance != bobAmount {
t.Fatalf("Bob has wrong balance: expected %v, got %v",
bobAmount, commitment.ourBalance)
}
// Settle HTLC and sign new commitment. // Settle HTLC and sign new commitment.
settleIndex, err := bobChannel.SettleHTLC(preimage) settleIndex, err := bobChannel.SettleHTLC(preimage)
@ -1132,41 +1137,15 @@ func TestCheckDustLimit(t *testing.T) {
t.Fatalf("state transition error: %v", err) t.Fatalf("state transition error: %v", err)
} }
commitment = aliceChannel.localCommitChain.tip() assertChannelState(aliceChannel, bobChannel, 2, 2, uint64(htlcAmount), 0)
if len(commitment.txn.TxOut) != 2 {
t.Fatalf("wrong number of outputs: expected %v, got %v",
2, len(commitment.txn.TxOut))
}
if commitment.ourBalance != aliceAmount-htlcAmount {
t.Fatalf("Alice has wrong balance: expected %v, got %v",
aliceAmount-htlcAmount, commitment.ourBalance)
}
if commitment.theirBalance != bobAmount+htlcAmount {
t.Fatalf("Alice has wrong balance for Bob: expected %v, got %v",
bobAmount, commitment.theirBalance)
}
commitment = bobChannel.localCommitChain.tip()
if len(commitment.txn.TxOut) != 2 {
t.Fatalf("wrong number of outputs: expected %v, got %v",
2, len(commitment.txn.TxOut))
}
if commitment.ourBalance != bobAmount+htlcAmount {
t.Fatalf("Bob has wrong balance: expected %v, got %v",
bobAmount+htlcAmount, commitment.ourBalance)
}
if commitment.theirBalance != aliceAmount-htlcAmount {
t.Fatalf("Bob has wrong balance for Alice: expected %v, got %v",
aliceAmount-htlcAmount, commitment.theirBalance)
}
// Next we will test when a non-HTLC output in the commitment // Next we will test when a non-HTLC output in the commitment
// transaction is below the dust limit. We create an HTLC that will // transaction is below the dust limit. We create an HTLC that will
// only leave a small enough amount to Alice such that Bob will // only leave a small enough amount to Alice such that Bob will
// consider it a dust output. // consider it a dust output.
aliceAmount = aliceChannel.channelState.OurBalance
bobAmount = bobChannel.channelState.OurBalance aliceAmount := btcutil.Amount(5e8)
htlcAmount2 := aliceAmount - htlcAmount htlcAmount2 := aliceAmount - btcutil.Amount(1000)
htlc, preimage = createHTLC(0, htlcAmount2) htlc, preimage = createHTLC(0, htlcAmount2)
if _, err := aliceChannel.AddHTLC(htlc); err != nil { if _, err := aliceChannel.AddHTLC(htlc); err != nil {
t.Fatalf("alice unable to add htlc: %v", err) t.Fatalf("alice unable to add htlc: %v", err)
@ -1179,34 +1158,8 @@ func TestCheckDustLimit(t *testing.T) {
} }
// From Alice's point of view, her output is bigger than the dust limit // From Alice's point of view, her output is bigger than the dust limit
commitment = aliceChannel.localCommitChain.tip()
if len(commitment.txn.TxOut) != 3 {
t.Fatalf("incorrect number of outputs in commitment transaction "+
"expected %v, got %v", 3, len(commitment.txn.TxOut))
}
if commitment.ourBalance != aliceAmount-htlcAmount2 {
t.Fatalf("Alice has wrong balance: expected %v, got %v",
aliceAmount-htlcAmount, commitment.ourBalance)
}
if commitment.theirBalance != bobAmount {
t.Fatalf("Alice has wrong balance for Bob: expected %v, got %v",
bobAmount, commitment.theirBalance)
}
// From Bob's point of view, Alice's output is lower than the dust limit // From Bob's point of view, Alice's output is lower than the dust limit
commitment = bobChannel.localCommitChain.tip() assertChannelState(aliceChannel, bobChannel, 3, 2, uint64(htlcAmount), 0)
if len(commitment.txn.TxOut) != 2 {
t.Fatalf("incorrect number of outputs in commitment transaction "+
"expected %v, got %v", 2, len(commitment.txn.TxOut))
}
if commitment.theirBalance != aliceAmount-htlcAmount2 {
t.Fatalf("Bob has wrong balance for Alice: expected %v, got %v",
aliceAmount-htlcAmount, commitment.theirBalance)
}
if commitment.ourBalance != bobAmount {
t.Fatalf("Bob has wrong balance: expected %v, got %v",
bobAmount+htlcAmount, commitment.ourBalance)
}
// Settle HTLC and sign new commitment. // Settle HTLC and sign new commitment.
settleIndex, err = bobChannel.SettleHTLC(preimage) settleIndex, err = bobChannel.SettleHTLC(preimage)
@ -1221,33 +1174,8 @@ func TestCheckDustLimit(t *testing.T) {
t.Fatalf("state transition error: %v", err) t.Fatalf("state transition error: %v", err)
} }
commitment = aliceChannel.localCommitChain.tip() assertChannelState(aliceChannel, bobChannel, 2, 1,
if len(commitment.txn.TxOut) != 2 { uint64(htlcAmount+htlcAmount2), 0)
t.Fatalf("incorrect number of outputs in commitment transaction, "+
"expected %v got %v", 2, len(commitment.txn.TxOut))
}
if commitment.ourBalance != aliceAmount-htlcAmount2 {
t.Fatalf("Alice has wrong balance: expected %v, got %v",
aliceAmount-htlcAmount, commitment.ourBalance)
}
if commitment.theirBalance != bobAmount+htlcAmount2 {
t.Fatalf("Alice has wrong balance for Bob: expected %v, got %v",
bobAmount, commitment.theirBalance)
}
commitment = bobChannel.localCommitChain.tip()
if len(commitment.txn.TxOut) != 1 {
t.Fatalf("incorrect number of outputs in commitment transaction, "+
"expected %v got %v", 1, len(commitment.txn.TxOut))
}
if commitment.ourBalance != bobAmount+htlcAmount2 {
t.Fatalf("Bob has wrong balance: expected %v, got %v",
bobAmount+htlcAmount, commitment.ourBalance)
}
if commitment.theirBalance != aliceAmount-htlcAmount2 {
t.Fatalf("Bob has wrong balance for Alice: expected %v, got %v",
aliceAmount-htlcAmount, commitment.theirBalance)
}
} }
func TestStateUpdatePersistence(t *testing.T) { func TestStateUpdatePersistence(t *testing.T) {
@ -1267,9 +1195,6 @@ func TestStateUpdatePersistence(t *testing.T) {
t.Fatalf("unable to sync bob's channel: %v", err) t.Fatalf("unable to sync bob's channel: %v", err)
} }
aliceStartingBalance := aliceChannel.channelState.OurBalance
bobStartingBalance := bobChannel.channelState.OurBalance
const numHtlcs = 4 const numHtlcs = 4
// Alice adds 3 HTLCs to the update log, while Bob adds a single HTLC. // Alice adds 3 HTLCs to the update log, while Bob adds a single HTLC.
@ -1281,7 +1206,7 @@ func TestStateUpdatePersistence(t *testing.T) {
rHash := sha256.Sum256(alicePreimage[:]) rHash := sha256.Sum256(alicePreimage[:])
h := &lnwire.UpdateAddHTLC{ h := &lnwire.UpdateAddHTLC{
PaymentHash: rHash, PaymentHash: rHash,
Amount: btcutil.Amount(500), Amount: btcutil.Amount(5000),
Expiry: uint32(10), Expiry: uint32(10),
} }
@ -1295,7 +1220,7 @@ func TestStateUpdatePersistence(t *testing.T) {
rHash := sha256.Sum256(bobPreimage[:]) rHash := sha256.Sum256(bobPreimage[:])
bobh := &lnwire.UpdateAddHTLC{ bobh := &lnwire.UpdateAddHTLC{
PaymentHash: rHash, PaymentHash: rHash,
Amount: btcutil.Amount(500), Amount: btcutil.Amount(5000),
Expiry: uint32(10), Expiry: uint32(10),
} }
if _, err := bobChannel.AddHTLC(bobh); err != nil { if _, err := bobChannel.AddHTLC(bobh); err != nil {
@ -1319,20 +1244,6 @@ func TestStateUpdatePersistence(t *testing.T) {
t.Fatalf("unable to complete bob's state transition: %v", err) t.Fatalf("unable to complete bob's state transition: %v", err)
} }
// The balances of both channels should be updated accordingly.
aliceBalance := aliceChannel.channelState.OurBalance
expectedAliceBalance := aliceStartingBalance - btcutil.Amount(1500)
bobBalance := bobChannel.channelState.OurBalance
expectedBobBalance := bobStartingBalance - btcutil.Amount(500)
if aliceBalance != expectedAliceBalance {
t.Fatalf("expected %v alice balance, got %v", int64(expectedAliceBalance),
int64(aliceBalance))
}
if bobBalance != expectedBobBalance {
t.Fatalf("expected %v bob balance, got %v", int64(expectedBobBalance),
int64(bobBalance))
}
// The latest commitment from both sides should have all the HTLCs. // The latest commitment from both sides should have all the HTLCs.
numAliceOutgoing := aliceChannel.localCommitChain.tail().outgoingHTLCs numAliceOutgoing := aliceChannel.localCommitChain.tail().outgoingHTLCs
numAliceIncoming := aliceChannel.localCommitChain.tail().incomingHTLCs numAliceIncoming := aliceChannel.localCommitChain.tail().incomingHTLCs
@ -1419,7 +1330,7 @@ func TestStateUpdatePersistence(t *testing.T) {
if bobChannel.localUpdateLog.Len() != if bobChannel.localUpdateLog.Len() !=
bobChannelNew.localUpdateLog.Len() { bobChannelNew.localUpdateLog.Len() {
t.Fatalf("bob log len: expected %v, got %v", t.Fatalf("bob log len: expected %v, got %v",
bobChannelNew.localUpdateLog.Len(), bobChannel.localUpdateLog.Len(),
bobChannelNew.localUpdateLog.Len()) bobChannelNew.localUpdateLog.Len())
} }
if bobChannel.remoteUpdateLog.Len() != if bobChannel.remoteUpdateLog.Len() !=
@ -1511,37 +1422,23 @@ func TestStateUpdatePersistence(t *testing.T) {
t.Fatalf("unable to update commitments: %v", err) t.Fatalf("unable to update commitments: %v", err)
} }
// The balances of both sides should have been updated accordingly.
aliceBalance = aliceChannelNew.channelState.OurBalance
expectedAliceBalance = aliceStartingBalance - btcutil.Amount(1000)
bobBalance = bobChannelNew.channelState.OurBalance
expectedBobBalance = bobStartingBalance + btcutil.Amount(1000)
if aliceBalance != expectedAliceBalance {
t.Fatalf("expected %v alice balance, got %v", expectedAliceBalance,
aliceBalance)
}
if bobBalance != expectedBobBalance {
t.Fatalf("expected %v bob balance, got %v", expectedBobBalance,
bobBalance)
}
// The amounts transferred should been updated as per the amounts in // The amounts transferred should been updated as per the amounts in
// the HTLCs // the HTLCs
if aliceChannelNew.channelState.TotalSatoshisSent != 1500 { if aliceChannelNew.channelState.TotalSatoshisSent != 15000 {
t.Fatalf("expected %v alice satoshis sent, got %v", t.Fatalf("expected %v alice satoshis sent, got %v",
3000, aliceChannelNew.channelState.TotalSatoshisSent) 15000, aliceChannelNew.channelState.TotalSatoshisSent)
} }
if aliceChannelNew.channelState.TotalSatoshisReceived != 500 { if aliceChannelNew.channelState.TotalSatoshisReceived != 5000 {
t.Fatalf("expected %v alice satoshis received, got %v", t.Fatalf("expected %v alice satoshis received, got %v",
1000, aliceChannelNew.channelState.TotalSatoshisReceived) 5000, aliceChannelNew.channelState.TotalSatoshisReceived)
} }
if bobChannelNew.channelState.TotalSatoshisSent != 500 { if bobChannelNew.channelState.TotalSatoshisSent != 5000 {
t.Fatalf("expected %v bob satoshis sent, got %v", t.Fatalf("expected %v bob satoshis sent, got %v",
1000, bobChannel.channelState.TotalSatoshisSent) 5000, bobChannel.channelState.TotalSatoshisSent)
} }
if bobChannelNew.channelState.TotalSatoshisReceived != 1500 { if bobChannelNew.channelState.TotalSatoshisReceived != 15000 {
t.Fatalf("expected %v bob satoshis sent, got %v", t.Fatalf("expected %v bob satoshis sent, got %v",
3000, bobChannel.channelState.TotalSatoshisSent) 15000, bobChannel.channelState.TotalSatoshisSent)
} }
} }
@ -1580,7 +1477,8 @@ func TestCancelHTLC(t *testing.T) {
// With the HTLC committed, Alice's balance should reflect the clearing // With the HTLC committed, Alice's balance should reflect the clearing
// of the new HTLC. // of the new HTLC.
aliceExpectedBalance := btcutil.Amount(btcutil.SatoshiPerBitcoin * 4) aliceExpectedBalance := btcutil.Amount(btcutil.SatoshiPerBitcoin*4) -
calcStaticFee(1)
if aliceChannel.channelState.OurBalance != aliceExpectedBalance { if aliceChannel.channelState.OurBalance != aliceExpectedBalance {
t.Fatalf("Alice's balance is wrong: expected %v, got %v", t.Fatalf("Alice's balance is wrong: expected %v, got %v",
aliceExpectedBalance, aliceChannel.channelState.OurBalance) aliceExpectedBalance, aliceChannel.channelState.OurBalance)
@ -1622,9 +1520,10 @@ func TestCancelHTLC(t *testing.T) {
} }
expectedBalance := btcutil.Amount(btcutil.SatoshiPerBitcoin * 5) expectedBalance := btcutil.Amount(btcutil.SatoshiPerBitcoin * 5)
if aliceChannel.channelState.OurBalance != expectedBalance { if aliceChannel.channelState.OurBalance != expectedBalance-calcStaticFee(0) {
t.Fatalf("balance is wrong: expected %v, got %v", t.Fatalf("balance is wrong: expected %v, got %v",
aliceChannel.channelState.OurBalance, expectedBalance) aliceChannel.channelState.OurBalance, expectedBalance-
calcStaticFee(0))
} }
if aliceChannel.channelState.TheirBalance != expectedBalance { if aliceChannel.channelState.TheirBalance != expectedBalance {
t.Fatalf("balance is wrong: expected %v, got %v", t.Fatalf("balance is wrong: expected %v, got %v",
@ -1634,9 +1533,10 @@ func TestCancelHTLC(t *testing.T) {
t.Fatalf("balance is wrong: expected %v, got %v", t.Fatalf("balance is wrong: expected %v, got %v",
bobChannel.channelState.OurBalance, expectedBalance) bobChannel.channelState.OurBalance, expectedBalance)
} }
if bobChannel.channelState.TheirBalance != expectedBalance { if bobChannel.channelState.TheirBalance != expectedBalance-calcStaticFee(0) {
t.Fatalf("balance is wrong: expected %v, got %v", t.Fatalf("balance is wrong: expected %v, got %v",
bobChannel.channelState.TheirBalance, expectedBalance) bobChannel.channelState.TheirBalance,
expectedBalance-calcStaticFee(0))
} }
} }
@ -1699,7 +1599,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
// Next we'll modify the current balances and dust limits such that // Next we'll modify the current balances and dust limits such that
// Bob's current balance is above _below_ his dust limit. // Bob's current balance is above _below_ his dust limit.
aliceBal := btcutil.Amount(btcutil.SatoshiPerBitcoin) aliceBal := btcutil.Amount(btcutil.SatoshiPerBitcoin)
bobBal := btcutil.Amount(500) bobBal := btcutil.Amount(250)
setBalances(aliceBal, bobBal) setBalances(aliceBal, bobBal)
// Attempt another cooperative channel closure. It should succeed // Attempt another cooperative channel closure. It should succeed
@ -1716,14 +1616,13 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
// The closure transaction should only have a single output, and that // The closure transaction should only have a single output, and that
// output should be Alice's balance. // output should be Alice's balance.
// TODO(roasbeef): remove -5000 after fees are no longer hard coded
if len(closeTx.TxOut) != 1 { if len(closeTx.TxOut) != 1 {
t.Fatalf("close tx has wrong number of outputs: expected %v "+ t.Fatalf("close tx has wrong number of outputs: expected %v "+
"got %v", 1, len(closeTx.TxOut)) "got %v", 1, len(closeTx.TxOut))
} }
if closeTx.TxOut[0].Value != int64(aliceBal-5000) { if closeTx.TxOut[0].Value != int64(aliceBal-calcStaticFee(0)) {
t.Fatalf("alice's balance is incorrect: expected %v, got %v", t.Fatalf("alice's balance is incorrect: expected %v, got %v",
aliceBal-5000, closeTx.TxOut[0].Value) aliceBal-calcStaticFee(0), closeTx.TxOut[0].Value)
} }
// Finally, we'll modify the current balances and dust limits such that // Finally, we'll modify the current balances and dust limits such that
@ -1745,7 +1644,6 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
// The closure transaction should only have a single output, and that // The closure transaction should only have a single output, and that
// output should be Bob's balance. // output should be Bob's balance.
// TODO(roasbeef): remove -5000 after fees are no longer hard coded
if len(closeTx.TxOut) != 1 { if len(closeTx.TxOut) != 1 {
t.Fatalf("close tx has wrong number of outputs: expected %v "+ t.Fatalf("close tx has wrong number of outputs: expected %v "+
"got %v", 1, len(closeTx.TxOut)) "got %v", 1, len(closeTx.TxOut))

@ -101,6 +101,20 @@ func assertReservationDeleted(res *lnwallet.ChannelReservation, t *testing.T) {
} }
} }
// calcStaticFee calculates appropriate fees for commitment transactions. This
// function provides a simple way to allow test balance assertions to take fee
// calculations into account.
// TODO(bvu): Refactor when dynamic fee estimation is added.
func calcStaticFee(numHTLCs int) btcutil.Amount {
const (
commitWeight = btcutil.Amount(724)
htlcWeight = 172
feePerByte = btcutil.Amount(250 * 4)
)
return feePerByte * (commitWeight +
btcutil.Amount(htlcWeight*numHTLCs)) / 1000
}
// bobNode represents the other party involved as a node within LN. Bob is our // bobNode represents the other party involved as a node within LN. Bob is our
// only "default-route", we have a direct connection with him. // only "default-route", we have a direct connection with him.
type bobNode struct { type bobNode struct {
@ -454,7 +468,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, wallet *lnwallet
// TODO(roasbeef): account for current hard-coded commit fee, // TODO(roasbeef): account for current hard-coded commit fee,
// need to remove bob all together // need to remove bob all together
chanCapacity := int64(10e8 + 5000) chanCapacity := int64(10e8)
// Alice responds with her output, change addr, multi-sig key and signatures. // Alice responds with her output, change addr, multi-sig key and signatures.
// Bob then responds with his signatures. // Bob then responds with his signatures.
bobsSigs, err := bobNode.signFundingTx(fundingTx) bobsSigs, err := bobNode.signFundingTx(fundingTx)
@ -572,9 +586,10 @@ func testCancelNonExistantReservation(miner *rpctest.Harness,
t.Log("Running cancel reservation tests") t.Log("Running cancel reservation tests")
feeRate := btcutil.Amount(wallet.FeeEstimator.EstimateFeePerWeight(1))
// Create our own reservation, give it some ID. // Create our own reservation, give it some ID.
res := lnwallet.NewChannelReservation(1000, 1000, 5000, wallet, 22, res := lnwallet.NewChannelReservation(1000, 1000, feeRate, wallet,
numReqConfs, 10) 22, numReqConfs, 10)
// Attempt to cancel this reservation. This should fail, we know // Attempt to cancel this reservation. This should fail, we know
// nothing of it. // nothing of it.
@ -691,7 +706,7 @@ func testSingleFunderReservationWorkflowInitiator(miner *rpctest.Harness,
chanReservation.FundingRedeemScript(), chanReservation.FundingRedeemScript(),
// TODO(roasbeef): account for current hard-coded fee, need to // TODO(roasbeef): account for current hard-coded fee, need to
// remove bobNode entirely // remove bobNode entirely
int64(fundingAmt)+5000) int64(fundingAmt))
if err != nil { if err != nil {
t.Fatalf("bob is unable to sign alice's commit tx: %v", err) t.Fatalf("bob is unable to sign alice's commit tx: %v", err)
} }
@ -781,6 +796,7 @@ func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,
// include any inputs or change addresses, as only Bob will construct // include any inputs or change addresses, as only Bob will construct
// the funding transaction. // the funding transaction.
bobContribution := bobNode.Contribution(ourContribution.CommitKey) bobContribution := bobNode.Contribution(ourContribution.CommitKey)
bobContribution.DustLimit = lnwallet.DefaultDustLimit()
if err := chanReservation.ProcessSingleContribution(bobContribution); err != nil { if err := chanReservation.ProcessSingleContribution(bobContribution); err != nil {
t.Fatalf("unable to process bob's contribution: %v", err) t.Fatalf("unable to process bob's contribution: %v", err)
} }
@ -815,7 +831,7 @@ func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,
ourContribution.MultiSigKey.SerializeCompressed(), ourContribution.MultiSigKey.SerializeCompressed(),
bobContribution.MultiSigKey.SerializeCompressed(), bobContribution.MultiSigKey.SerializeCompressed(),
// TODO(roasbeef): account for hard-coded fee, remove bob node // TODO(roasbeef): account for hard-coded fee, remove bob node
int64(capacity)+5000) int64(capacity))
if err != nil { if err != nil {
t.Fatalf("unable to generate multi-sig output: %v", err) t.Fatalf("unable to generate multi-sig output: %v", err)
} }
@ -843,10 +859,11 @@ func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,
// Next, manually create Alice's commitment transaction, signing the // Next, manually create Alice's commitment transaction, signing the
// fully sorted and state hinted transaction. // fully sorted and state hinted transaction.
fundingTxIn := wire.NewTxIn(fundingOutpoint, nil, nil) fundingTxIn := wire.NewTxIn(fundingOutpoint, nil, nil)
aliceCommitTx, err := lnwallet.CreateCommitTx(fundingTxIn, aliceCommitTx, err := lnwallet.CreateCommitTx(fundingTxIn,
ourContribution.CommitKey, bobContribution.CommitKey, ourContribution.CommitKey, bobContribution.CommitKey,
ourContribution.RevocationKey, ourContribution.CsvDelay, 0, ourContribution.RevocationKey, ourContribution.CsvDelay, 0,
capacity, lnwallet.DefaultDustLimit()) capacity-calcStaticFee(0), lnwallet.DefaultDustLimit())
if err != nil { if err != nil {
t.Fatalf("unable to create alice's commit tx: %v", err) t.Fatalf("unable to create alice's commit tx: %v", err)
} }
@ -857,7 +874,7 @@ func testSingleFunderReservationWorkflowResponder(miner *rpctest.Harness,
} }
bobCommitSig, err := bobNode.signCommitTx(aliceCommitTx, bobCommitSig, err := bobNode.signCommitTx(aliceCommitTx,
// TODO(roasbeef): account for hard-coded fee, remove bob node // TODO(roasbeef): account for hard-coded fee, remove bob node
fundingRedeemScript, int64(capacity)+5000) fundingRedeemScript, int64(capacity))
if err != nil { if err != nil {
t.Fatalf("unable to sign alice's commit tx: %v", err) t.Fatalf("unable to sign alice's commit tx: %v", err)
} }

@ -155,6 +155,8 @@ func NewChannelReservation(capacity, fundingAmt btcutil.Amount, minFeeRate btcut
initiator bool initiator bool
) )
commitFee := minFeeRate * commitWeight / 1000
// If we're the responder to a single-funder reservation, then we have // If we're the responder to a single-funder reservation, then we have
// no initial balance in the channel unless the remote party is pushing // no initial balance in the channel unless the remote party is pushing
// some funds to us within the first commitment state. // some funds to us within the first commitment state.
@ -166,20 +168,22 @@ func NewChannelReservation(capacity, fundingAmt btcutil.Amount, minFeeRate btcut
// TODO(roasbeef): need to rework fee structure in general and // TODO(roasbeef): need to rework fee structure in general and
// also when we "unlock" dual funder within the daemon // also when we "unlock" dual funder within the daemon
if capacity == fundingAmt+commitFee { if capacity == fundingAmt {
// If we're initiating a single funder workflow, then // If we're initiating a single funder workflow, then
// we pay all the initial fees within the commitment // we pay all the initial fees within the commitment
// transaction. We also deduct our balance by the // transaction. We also deduct our balance by the
// amount pushed as part of the initial state. // amount pushed as part of the initial state.
ourBalance = capacity - commitFee - pushSat ourBalance = capacity - commitFee - pushSat
theirBalance = capacity - fundingAmt + pushSat
} else { } else {
// Otherwise, this is a dual funder workflow where both // Otherwise, this is a dual funder workflow where both
// slides split the amount funded and the commitment // slides split the amount funded and the commitment
// fee. // fee.
ourBalance = fundingAmt - commitFee ourBalance = fundingAmt - (commitFee / 2)
theirBalance = capacity - fundingAmt -
(commitFee / 2) + pushSat
} }
theirBalance = capacity - fundingAmt - commitFee + pushSat
initiator = true initiator = true
} }

@ -37,7 +37,8 @@ const (
// rotations, etc. // rotations, etc.
identityKeyIndex = hdkeychain.HardenedKeyStart + 2 identityKeyIndex = hdkeychain.HardenedKeyStart + 2
commitFee = 5000 commitWeight = btcutil.Amount(724)
htlcWeight = 172
) )
var ( var (
@ -526,8 +527,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
} }
id := atomic.AddUint64(&l.nextFundingID, 1) id := atomic.AddUint64(&l.nextFundingID, 1)
totalCapacity := req.capacity + commitFee reservation := NewChannelReservation(req.capacity, req.fundingAmount,
reservation := NewChannelReservation(totalCapacity, req.fundingAmount,
req.minFeeRate, l, id, req.numConfs, req.pushSat) req.minFeeRate, l, id, req.numConfs, req.pushSat)
// Grab the mutex on the ChannelReservation to ensure thread-safety // Grab the mutex on the ChannelReservation to ensure thread-safety
@ -551,9 +551,8 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
if req.fundingAmount != 0 { if req.fundingAmount != 0 {
// TODO(roasbeef): consult model for proper fee rate on funding // TODO(roasbeef): consult model for proper fee rate on funding
// tx // tx
feeRate := uint64(10) err := l.selectCoinsAndChange(uint64(req.minFeeRate),
amt := req.fundingAmount + commitFee req.fundingAmount, ourContribution)
err := l.selectCoinsAndChange(feeRate, amt, ourContribution)
if err != nil { if err != nil {
req.err <- err req.err <- err
req.resp <- nil req.resp <- nil

@ -367,7 +367,7 @@ func TestEdgeUpdateNotification(t *testing.T) {
} }
// TODO(roasbeef): this is a hack, needs to be removed // TODO(roasbeef): this is a hack, needs to be removed
// after commitment fees are dynamic. // after commitment fees are dynamic.
if edgeUpdate.Capacity != chanValue-5000 { if edgeUpdate.Capacity != chanValue {
t.Fatalf("capacity of edge doesn't match: "+ t.Fatalf("capacity of edge doesn't match: "+
"expected %v, got %v", chanValue, edgeUpdate.Capacity) "expected %v, got %v", chanValue, edgeUpdate.Capacity)
} }
@ -682,7 +682,7 @@ func TestChannelCloseNotification(t *testing.T) {
} }
// TODO(roasbeef): this is a hack, needs to be removed // TODO(roasbeef): this is a hack, needs to be removed
// after commitment fees are dynamic. // after commitment fees are dynamic.
if closedChan.Capacity != chanValue-5000 { if closedChan.Capacity != chanValue {
t.Fatalf("capacity of closed channel doesn't match: "+ t.Fatalf("capacity of closed channel doesn't match: "+
"expected %v, got %v", chanValue, closedChan.Capacity) "expected %v, got %v", chanValue, closedChan.Capacity)
} }

@ -622,7 +622,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
// TODO(roasbeef): this is a hack, needs to be removed // TODO(roasbeef): this is a hack, needs to be removed
// after commitment fees are dynamic. // after commitment fees are dynamic.
msg.Capacity = btcutil.Amount(chanUtxo.Value) - btcutil.Amount(5000) msg.Capacity = btcutil.Amount(chanUtxo.Value)
msg.ChannelPoint = *fundingPoint msg.ChannelPoint = *fundingPoint
if err := r.cfg.Graph.AddChannelEdge(msg); err != nil { if err := r.cfg.Graph.AddChannelEdge(msg); err != nil {
return errors.Errorf("unable to add edge: %v", err) return errors.Errorf("unable to add edge: %v", err)