From 549688d79351980c8b9015dabf73fe4e7b931a5e Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sun, 30 Jul 2017 12:44:13 -0700 Subject: [PATCH] lnwallet: remove isDustLocal and isDustRemote, replace w/ htlcIsDust MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit modifies the way we account for dust HTLC’s within the commitment state machine when creating and validating new states. Previously, an HTLC was dust if the amount of the HTLC was below the dustLimit of the commitment chain. Now, with the HTLC covenant transaction, the value of the HTLC also needs to cover the required fee of the HTLC covenant transaction at the specified fee rate of the commitment chain. As a result, we now determine if an HTLC is dust or not, only at the commitment site, using the new htlcIsDust function. --- lnwallet/channel.go | 95 ++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index ec839bc3..cc358238 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -182,11 +182,6 @@ type PaymentDescriptor struct { // into the log to the HTLC being modified. EntryType updateType - // isDust[Local|Remote] denotes if this HTLC is below the dust limit in - // locally or remotely. - isDustLocal bool - isDustRemote bool - // isForwarded denotes if an incoming HTLC has been forwarded to any // possible upstream peers in the route. isForwarded bool @@ -1139,9 +1134,59 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven func (lc *LightningChannel) Stop() { if !atomic.CompareAndSwapInt32(&lc.shutdown, 0, 1) { return +// htlcTimeoutFee returns the fee in satoshis required for an HTLC timeout +// transaction based on the current fee rate. +func htlcTimeoutFee(feePerKw btcutil.Amount) btcutil.Amount { + return (feePerKw * HtlcTimeoutWeight) / 1000 +} + +// htlcSuccessFee returns the fee in satoshis required for an HTLC success +// transaction based on the current fee rate. +func htlcSuccessFee(feePerKw btcutil.Amount) btcutil.Amount { + return (feePerKw * HtlcSuccessWeight) / 1000 +} + +// htlcIsDust determines if an HTLC output is dust or not depending on two +// bits: if the HTLC is incoming and if the HTLC will be placed on our +// commitment transaction, or theirs. These two pieces of information are +// require as we currently used second-level HTLC transactions ass off-chain +// covenants. Depending on the two bits, we'll either be using a timeout or +// success transaction which have different weights. +func htlcIsDust(incoming, ourCommit bool, + feePerKw, htlcAmt, dustLimit btcutil.Amount) bool { + + // First we'll determine the fee required for this HTLC based on if this is + // an incoming HTLC or not, and also on whose commitment transaction it + // will be placed on. + var htlcFee btcutil.Amount + switch { + + // If this is an incoming HTLC on our commitment transaction, then the + // second-level transaction will be a success transaction. + case incoming && ourCommit: + htlcFee = htlcSuccessFee(feePerKw) + + // If this is an incoming HTLC on their commitment transaction, then + // we'll be using a second-level timeout transaction as they've added + // this HTLC. + case incoming && !ourCommit: + htlcFee = htlcTimeoutFee(feePerKw) + + // If this is an outgoing HTLC on our commitment transaction, then + // we'll be using a timeout transaction as we're the sender of the + // HTLC. + case !incoming && ourCommit: + htlcFee = htlcTimeoutFee(feePerKw) + + // If this is an outgoing HTLC on their commitment transaction, then + // we'll be using an HTLC success transaction as they're the receiver + // of this HTLC. + case !incoming && !ourCommit: + htlcFee = htlcTimeoutFee(feePerKw) } close(lc.quit) + return (htlcAmt - htlcFee) < dustLimit } // restoreStateLogs runs through the current locked-in HTLCs from the point of @@ -1192,8 +1237,10 @@ func (lc *LightningChannel) restoreStateLogs() error { // outputs within the commitment transaction. As we'll mark // dust with a special output index in the on-disk state // snapshot. - isDustLocal := htlc.Amt < lc.channelState.OurDustLimit - isDustRemote := htlc.Amt < lc.channelState.TheirDustLimit + isDustLocal := htlcIsDust(htlc.Incoming, true, feeRate, + htlc.Amt, localChanCfg.DustLimit) + isDustRemote := htlcIsDust(htlc.Incoming, false, feeRate, + htlc.Amt, remoteChanCfg.DustLimit) if !isDustLocal { ourP2WSH, err = lc.genHtlcScript(htlc.Incoming, true, htlc.RefundTimeout, ourDelay, remoteKey, @@ -1218,8 +1265,6 @@ func (lc *LightningChannel) restoreStateLogs() error { EntryType: Add, addCommitHeightRemote: pastHeight, addCommitHeightLocal: pastHeight, - isDustLocal: isDustLocal, - isDustRemote: isDustRemote, ourPkScript: ourP2WSH, theirPkScript: theirP2WSH, } @@ -1436,8 +1481,8 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool, } for _, htlc := range filteredHTLCView.ourUpdates { - if (ourCommitTx && htlc.isDustLocal) || - (!ourCommitTx && htlc.isDustRemote) { + if htlcIsDust(false, !remoteChain, feePerKw, htlc.Amount, + dustLimit) { continue } @@ -1448,8 +1493,8 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool, } } for _, htlc := range filteredHTLCView.theirUpdates { - if (ourCommitTx && htlc.isDustLocal) || - (!ourCommitTx && htlc.isDustRemote) { + if htlcIsDust(true, !remoteChain, feePerKw, htlc.Amount, + dustLimit) { continue } @@ -2204,13 +2249,11 @@ func (lc *LightningChannel) AddHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, error) lc.availableLocalBalance -= htlc.Amount pd := &PaymentDescriptor{ - EntryType: Add, - RHash: PaymentHash(htlc.PaymentHash), - Timeout: htlc.Expiry, - Amount: htlc.Amount, - Index: lc.localUpdateLog.logIndex, - isDustLocal: htlc.Amount < lc.channelState.OurDustLimit, - isDustRemote: htlc.Amount < lc.channelState.TheirDustLimit, + EntryType: Add, + RHash: PaymentHash(htlc.PaymentHash), + Timeout: htlc.Expiry, + Amount: htlc.Amount, + Index: lc.localUpdateLog.logIndex, } lc.localUpdateLog.appendUpdate(pd) @@ -2231,13 +2274,11 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, err } pd := &PaymentDescriptor{ - EntryType: Add, - RHash: PaymentHash(htlc.PaymentHash), - Timeout: htlc.Expiry, - Amount: htlc.Amount, - Index: lc.remoteUpdateLog.logIndex, - isDustLocal: htlc.Amount < lc.channelState.OurDustLimit, - isDustRemote: htlc.Amount < lc.channelState.TheirDustLimit, + EntryType: Add, + RHash: PaymentHash(htlc.PaymentHash), + Timeout: htlc.Expiry, + Amount: htlc.Amount, + Index: lc.remoteUpdateLog.logIndex, } lc.remoteUpdateLog.appendUpdate(pd)