lnwallet: when calc'ing fee for commitment tx, use current fee-per-kw

This commit modifies the fee calculation logic when creating or
accepting a new commitment transaction to use the set FeePerKw within
the channel rather then re-query the estimator each time. The prior
behavior was benign as we currently use a static fee estimator, but the
dynamic setting this could’ve caused a state divergence.
This commit is contained in:
Olaoluwa Osuntokun 2017-05-16 19:05:12 -07:00
parent 82f591dbab
commit e689ef61dd
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
2 changed files with 30 additions and 21 deletions

@ -1256,10 +1256,8 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
commitChain = lc.localCommitChain commitChain = lc.localCommitChain
} }
// TODO(roasbeef): don't assume view is always fetched from tip? ourBalance := commitChain.tip().ourBalance
var ourBalance, theirBalance btcutil.Amount theirBalance := commitChain.tip().theirBalance
ourBalance = commitChain.tip().ourBalance
theirBalance = commitChain.tip().theirBalance
// Add the fee from the previous commitment state back to the // Add the fee from the previous commitment state back to the
// initiator's balance, so that the fee can be recalculated and // initiator's balance, so that the fee can be recalculated and
@ -1307,20 +1305,28 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
numHTLCs++ numHTLCs++
} }
// Calculate the fee for the commitment transaction based on its size. // Next, we'll calculate the fee for the commitment transaction based
commitFee := btcutil.Amount(lc.feeEstimator.EstimateFeePerWeight(1)) * // on its total weight. Once we have the total weight, we'll multiply
(commitWeight + btcutil.Amount(htlcWeight*numHTLCs)) / 1000 // by the current fee-per-kw, then divide by 1000 to get the proper
// fee.
totalCommitWeight := commitWeight + btcutil.Amount(htlcWeight*numHTLCs)
commitFee := (lc.channelState.FeePerKw * totalCommitWeight) / 1000
// Currently, within the protocol, the initiator always pays the fees.
// So we'll subtract the fee amount from the balance of the current
// initiator.
if lc.channelState.IsInitiator { if lc.channelState.IsInitiator {
ourBalance = ourBalance - commitFee ourBalance = ourBalance - commitFee
} else if !lc.channelState.IsInitiator { } else if !lc.channelState.IsInitiator {
theirBalance = theirBalance - commitFee theirBalance = theirBalance - commitFee
} }
var selfKey *btcec.PublicKey var (
var remoteKey *btcec.PublicKey selfKey *btcec.PublicKey
var delay uint32 remoteKey *btcec.PublicKey
var delayBalance, p2wkhBalance btcutil.Amount delay uint32
delayBalance, p2wkhBalance btcutil.Amount
)
if remoteChain { if remoteChain {
selfKey = lc.channelState.TheirCommitKey selfKey = lc.channelState.TheirCommitKey
remoteKey = lc.channelState.OurCommitKey remoteKey = lc.channelState.OurCommitKey
@ -2542,8 +2548,7 @@ func (lc *LightningChannel) InitCooperativeClose() ([]byte, *chainhash.Hash, err
// Calculate the fee for the commitment transaction based on its size. // Calculate the fee for the commitment transaction based on its size.
// For a cooperative close, there should be no HTLCs. // For a cooperative close, there should be no HTLCs.
commitFee := btcutil.Amount(lc.feeEstimator.EstimateFeePerWeight(1)) * commitFee := (lc.channelState.FeePerKw * commitWeight) / 1000
commitWeight / 1000
if lc.channelState.IsInitiator { if lc.channelState.IsInitiator {
lc.channelState.OurBalance = lc.channelState.OurBalance - commitFee lc.channelState.OurBalance = lc.channelState.OurBalance - commitFee
@ -2603,8 +2608,8 @@ func (lc *LightningChannel) CompleteCooperativeClose(remoteSig []byte) (*wire.Ms
// Calculate the fee for the commitment transaction based on its size. // Calculate the fee for the commitment transaction based on its size.
// For a cooperative close, there should be no HTLCs. // For a cooperative close, there should be no HTLCs.
commitFee := btcutil.Amount(lc.feeEstimator.EstimateFeePerWeight(1)) * // TODO(roasbeef): should be using fee passed in
commitWeight / 1000 commitFee := (lc.channelState.FeePerKw * commitWeight) / 1000
if lc.channelState.IsInitiator { if lc.channelState.IsInitiator {
lc.channelState.OurBalance = lc.channelState.OurBalance - commitFee lc.channelState.OurBalance = lc.channelState.OurBalance - commitFee

@ -186,7 +186,7 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
channelCapacity := btcutil.Amount(10 * 1e8) channelCapacity := btcutil.Amount(10 * 1e8)
channelBal := channelCapacity / 2 channelBal := channelCapacity / 2
aliceDustLimit := btcutil.Amount(200) aliceDustLimit := btcutil.Amount(200)
bobDustLimit := btcutil.Amount(800) bobDustLimit := btcutil.Amount(1300)
csvTimeoutAlice := uint32(5) csvTimeoutAlice := uint32(5)
csvTimeoutBob := uint32(4) csvTimeoutBob := uint32(4)
@ -244,10 +244,12 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
var obsfucator [StateHintSize]byte var obsfucator [StateHintSize]byte
copy(obsfucator[:], aliceFirstRevoke[:]) copy(obsfucator[:], aliceFirstRevoke[:])
feePerKw := btcutil.Amount(6000)
aliceChannelState := &channeldb.OpenChannel{ aliceChannelState := &channeldb.OpenChannel{
IdentityPub: aliceKeyPub, IdentityPub: aliceKeyPub,
ChanID: prevOut, ChanID: prevOut,
ChanType: channeldb.SingleFunder, ChanType: channeldb.SingleFunder,
FeePerKw: feePerKw,
IsInitiator: true, IsInitiator: true,
StateHintObsfucator: obsfucator, StateHintObsfucator: obsfucator,
OurCommitKey: aliceKeyPub, OurCommitKey: aliceKeyPub,
@ -272,6 +274,7 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
} }
bobChannelState := &channeldb.OpenChannel{ bobChannelState := &channeldb.OpenChannel{
IdentityPub: bobKeyPub, IdentityPub: bobKeyPub,
FeePerKw: feePerKw,
ChanID: prevOut, ChanID: prevOut,
ChanType: channeldb.SingleFunder, ChanType: channeldb.SingleFunder,
IsInitiator: false, IsInitiator: false,
@ -306,7 +309,7 @@ func createTestChannels(revocationWindow int) (*LightningChannel, *LightningChan
bobSigner := &mockSigner{bobKeyPriv} bobSigner := &mockSigner{bobKeyPriv}
notifier := &mockNotfier{} notifier := &mockNotfier{}
estimator := &StaticFeeEstimator{50, 6} estimator := &StaticFeeEstimator{24, 6}
channelAlice, err := NewLightningChannel(aliceSigner, notifier, channelAlice, err := NewLightningChannel(aliceSigner, notifier,
estimator, aliceChannelState) estimator, aliceChannelState)
@ -614,7 +617,7 @@ func TestCheckCommitTxSize(t *testing.T) {
} }
actualCost := blockchain.GetTransactionWeight(btcutil.NewTx(commitTx)) actualCost := blockchain.GetTransactionWeight(btcutil.NewTx(commitTx))
estimatedCost := estimateCommitTxCost(count, false) estimatedCost := estimateCommitTxWeight(count, false)
diff := int(estimatedCost - actualCost) diff := int(estimatedCost - actualCost)
if 0 > diff || BaseCommitmentTxSizeEstimationError < diff { if 0 > diff || BaseCommitmentTxSizeEstimationError < diff {
@ -1143,9 +1146,10 @@ func TestCheckDustLimit(t *testing.T) {
// 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.
// TODO(roasbeef): test needs to be fixed after reserves and proper
// rolling over of dust into fees is done
aliceAmount := btcutil.Amount(5e8) aliceAmount := btcutil.Amount(5e8)
htlcAmount2 := aliceAmount - btcutil.Amount(1000) htlcAmount2 := aliceAmount - btcutil.Amount(6100)
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)
@ -1622,7 +1626,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
} }
if closeTx.TxOut[0].Value != int64(aliceBal-calcStaticFee(0)) { 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-calcStaticFee(0), closeTx.TxOut[0].Value) int64(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