diff --git a/channeldb/channel.go b/channeldb/channel.go index 7792407e..b276704e 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -68,7 +68,7 @@ var ( updatePrefix = []byte("uup") satSentPrefix = []byte("ssp") satReceivedPrefix = []byte("srp") - netFeesPrefix = []byte("ntp") + commitFeePrefix = []byte("cfp") isPendingPrefix = []byte("pdg") openHeightPrefix = []byte("open-height-prefix") @@ -181,6 +181,13 @@ type OpenChannel struct { // channel directly spendable by the remote node. TheirBalance btcutil.Amount + // CommitFee is the amount calculated to be paid in fees for the + // current set of commitment transactions. The fee amount is + // persisted with the channel in order to allow the fee amount to be + // removed and recalculated with each channel state update, including + // updates that happen after a system restart. + CommitFee btcutil.Amount + // OurCommitKey is the latest version of the commitment state, // broadcast able by us. OurCommitTx *wire.MsgTx @@ -410,6 +417,7 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *wire.MsgTx, c.TheirBalance = delta.RemoteBalance c.NumUpdates = delta.UpdateNum c.Htlcs = delta.Htlcs + c.CommitFee = delta.CommitFee // First we'll write out the current latest dynamic channel // state: the current channel balance, the number of updates, @@ -424,6 +432,9 @@ func (c *OpenChannel) UpdateCommitment(newCommitment *wire.MsgTx, if err := putChanNumUpdates(chanBucket, c); err != nil { return err } + if err := putChanCommitFee(chanBucket, c); err != nil { + return err + } if err := putChanCommitTxns(nodeChanBucket, c); err != nil { return err } @@ -492,6 +503,10 @@ type ChannelDelta struct { // update number. RemoteBalance btcutil.Amount + // CommitFee is the fee that has been subtracted from the channel + // initiator's balance at this point in the commitment chain. + CommitFee btcutil.Amount + // UpdateNum is the update number that this ChannelDelta represents the // total number of commitment updates to this point. This can be viewed // as sort of a "commitment height" as this number is monotonically @@ -990,6 +1005,9 @@ func putOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket, if err := putChanOpenHeight(openChanBucket, channel); err != nil { return err } + if err := putChanCommitFee(openChanBucket, channel); err != nil { + return err + } // Next, write out the fields of the channel update less frequently. if err := putChannelIDs(nodeChanBucket, channel); err != nil { @@ -1080,6 +1098,9 @@ func fetchOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket, if err := fetchChanOpenHeight(openChanBucket, channel); err != nil { return nil, err } + if err = fetchChanCommitFee(openChanBucket, channel); err != nil { + return nil, err + } return channel, nil } @@ -1113,6 +1134,9 @@ func deleteOpenChannel(openChanBucket *bolt.Bucket, nodeChanBucket *bolt.Bucket, if err := deleteChanOpenHeight(openChanBucket, channelID); err != nil { return err } + if err := deleteChanCommitFee(openChanBucket, channelID); err != nil { + return err + } // Finally, delete all the fields directly within the node's channel // bucket. @@ -1591,6 +1615,46 @@ func deleteChanCommitKeys(nodeChanBucket *bolt.Bucket, chanID []byte) error { return nodeChanBucket.Delete(commitKey) } +func putChanCommitFee(openChanBucket *bolt.Bucket, channel *OpenChannel) error { + scratch := make([]byte, 8) + byteOrder.PutUint64(scratch, uint64(channel.CommitFee)) + + var b bytes.Buffer + if err := writeOutpoint(&b, channel.ChanID); err != nil { + return err + } + + keyPrefix := make([]byte, 3+b.Len()) + copy(keyPrefix, commitFeePrefix) + copy(keyPrefix[3:], b.Bytes()) + + return openChanBucket.Put(keyPrefix, scratch) +} + +func fetchChanCommitFee(openChanBucket *bolt.Bucket, channel *OpenChannel) error { + var b bytes.Buffer + if err := writeOutpoint(&b, channel.ChanID); err != nil { + return err + } + + keyPrefix := make([]byte, 3+b.Len()) + copy(keyPrefix, commitFeePrefix) + copy(keyPrefix[3:], b.Bytes()) + + commitFeeBytes := openChanBucket.Get(keyPrefix) + channel.CommitFee = btcutil.Amount(byteOrder.Uint64(commitFeeBytes)) + + return nil +} + +func deleteChanCommitFee(openChanBucket *bolt.Bucket, chanID []byte) error { + commitFeeKey := make([]byte, 3+len(chanID)) + copy(commitFeeKey, commitFeePrefix) + copy(commitFeeKey[3:], chanID) + + return openChanBucket.Delete(commitFeeKey) +} + func fetchChanCommitKeys(nodeChanBucket *bolt.Bucket, channel *OpenChannel) error { // Construct the key which stores the commitment keys: ckk || channelID. @@ -2119,6 +2183,11 @@ func serializeChannelDelta(w io.Writer, delta *ChannelDelta) error { } } + byteOrder.PutUint64(scratch[:], uint64(delta.CommitFee)) + if _, err := w.Write(scratch[:]); err != nil { + return err + } + return nil } @@ -2157,6 +2226,10 @@ func deserializeChannelDelta(r io.Reader) (*ChannelDelta, error) { delta.Htlcs[i] = htlc } + if _, err := r.Read(scratch[:]); err != nil { + return nil, err + } + delta.CommitFee = btcutil.Amount(byteOrder.Uint64(scratch[:])) return delta, nil } diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 6b570211..b0a2e558 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -232,6 +232,11 @@ type commitment struct { ourBalance btcutil.Amount theirBalance btcutil.Amount + // fee is the amount that will be paid as fees for this commitment + // transaction. The fee is recorded here so that it can be added + // back and recalculated for each new update to the channel state. + fee btcutil.Amount + // htlcs is the set of HTLCs which remain unsettled within this // commitment. outgoingHTLCs []PaymentDescriptor @@ -251,6 +256,7 @@ func (c *commitment) toChannelDelta(ourCommit bool) (*channeldb.ChannelDelta, er LocalBalance: c.ourBalance, RemoteBalance: c.theirBalance, UpdateNum: c.height, + CommitFee: c.fee, Htlcs: make([]*channeldb.HTLC, 0, numHtlcs), } @@ -1181,6 +1187,8 @@ func (lc *LightningChannel) restoreStateLogs() error { lc.localCommitChain.tail().theirMessageIndex = theirCounter lc.remoteCommitChain.tail().ourMessageIndex = ourCounter lc.remoteCommitChain.tail().theirMessageIndex = theirCounter + lc.localCommitChain.tail().fee = lc.channelState.CommitFee + lc.remoteCommitChain.tail().fee = lc.channelState.CommitFee return nil } @@ -1245,12 +1253,13 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool, // TODO(roasbeef): don't assume view is always fetched from tip? var ourBalance, theirBalance btcutil.Amount - if commitChain.tip() == nil { - ourBalance = lc.channelState.OurBalance - theirBalance = lc.channelState.TheirBalance - } else { - ourBalance = commitChain.tip().ourBalance - theirBalance = commitChain.tip().theirBalance + ourBalance = commitChain.tip().ourBalance + theirBalance = commitChain.tip().theirBalance + + if lc.channelState.IsInitiator { + ourBalance = ourBalance + commitChain.tip().fee + } else if !lc.channelState.IsInitiator { + theirBalance = theirBalance + commitChain.tip().fee } nextHeight := commitChain.tip().height + 1 diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go index 61d8ac6b..74c13c8e 100644 --- a/lnwallet/reservation.go +++ b/lnwallet/reservation.go @@ -215,6 +215,7 @@ func NewChannelReservation(capacity, fundingAmt btcutil.Amount, minFeeRate btcut TheirBalance: theirBalance, MinFeePerKb: minFeeRate, Db: wallet.ChannelDB, + CommitFee: commitFee, }, numConfsToOpen: numConfs, pushSat: pushSat,