Skip to content

Commit

Permalink
lnwallet: return balance changes rather than modifying references
Browse files Browse the repository at this point in the history
Here we return the balance deltas from evaluateHTLCView rather than
passing in references to variables that will be modified. It is a
far cleaner and compositional approach which allows readers of this
code to more effectively reason about the code without having to
keep the whole codebase in their head.
  • Loading branch information
ProofOfKeags committed Sep 12, 2024
1 parent 62114ea commit 1a3d207
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 62 deletions.
111 changes: 58 additions & 53 deletions lnwallet/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2777,10 +2777,9 @@ func fundingTxIn(chanState *channeldb.OpenChannel) wire.TxIn {
// 1. The new htlcView reflecting the current channel state.
// 2. A Dual of the updates which have not yet been committed in
// 'whoseCommitChain's commitment chain.
func (lc *LightningChannel) evaluateHTLCView(view *HtlcView, ourBalance,
theirBalance *lnwire.MilliSatoshi, nextHeight uint64,
whoseCommitChain lntypes.ChannelParty) (*HtlcView,
lntypes.Dual[[]*paymentDescriptor], error) {
func (lc *LightningChannel) evaluateHTLCView(view *HtlcView,
whoseCommitChain lntypes.ChannelParty, nextHeight uint64) (*HtlcView,
lntypes.Dual[[]*paymentDescriptor], lntypes.Dual[int64], error) {

// We initialize the view's fee rate to the fee rate of the unfiltered
// view. If any fee updates are found when evaluating the view, it will
Expand Down Expand Up @@ -2812,6 +2811,8 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView, ourBalance,
Remote: fn.NewSet[uint64](),
}

balanceDeltas := lntypes.Dual[int64]{}

parties := [2]lntypes.ChannelParty{lntypes.Local, lntypes.Remote}
for _, party := range parties {
// First we run through non-add entries in both logs,
Expand All @@ -2832,7 +2833,8 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView, ourBalance,
entry, whoseCommitChain, party.CounterParty(),
)
if err != nil {
return nil, noUncommitted, err
noDeltas := lntypes.Dual[int64]{}
return nil, noUncommitted, noDeltas, err
}

skipSet := skip.GetForParty(party.CounterParty())
Expand All @@ -2843,41 +2845,30 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView, ourBalance,
if rmvHeight == 0 {
switch {
// If an incoming HTLC is being settled, then
// this means that we've received the preimage
// either from another subsystem, or the
// upstream peer in the route. Therefore, we
// increase our balance by the HTLC amount.
case party.CounterParty() == lntypes.Remote &&
entry.EntryType == Settle:

*ourBalance += entry.Amount
// this means that the preimage has been
// received by the settling party Therefore, we
// increase the settling party's balance by the
// HTLC amount.
case entry.EntryType == Settle:
delta := int64(entry.Amount)
balanceDeltas.ModifyForParty(
party,
func(acc int64) int64 {
return acc + delta
},
)

// Otherwise, this HTLC is being failed out,
// therefore the value of the HTLC should
// return to the remote party.
case party.CounterParty() == lntypes.Remote &&
entry.EntryType != Settle:

*theirBalance += entry.Amount

// If an outgoing HTLC is being settled, then
// this means that the downstream party
// resented the preimage or learned of it via a
// downstream peer. In either case, we credit
// their settled value with the value of the
// HTLC.
case party.CounterParty() == lntypes.Local &&
entry.EntryType == Settle:

*theirBalance += entry.Amount

// Otherwise, one of our outgoing HTLC's has
// timed out, so the value of the HTLC should
// be returned to our settled balance.
case party.CounterParty() == lntypes.Local &&
entry.EntryType != Settle:

*ourBalance += entry.Amount
// return to the failing party's counterparty.
case entry.EntryType != Settle:
delta := int64(entry.Amount)
balanceDeltas.ModifyForParty(
party.CounterParty(),
func(acc int64) int64 {
return acc + delta
},
)
}
}
}
Expand All @@ -2898,19 +2889,19 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView, ourBalance,
addHeights := &entry.addCommitHeights
addHeight := addHeights.GetForParty(whoseCommitChain)
if addHeight == 0 {
if party == lntypes.Remote {
// If this is a new incoming
// (un-committed) HTLC, then we need
// to update their balance accordingly
// by subtracting the amount of the
// HTLC that are funds pending.
*theirBalance -= entry.Amount
} else {
// Similarly, we need to debit our
// balance if this is an out going HTLC
// to reflect the pending balance.
*ourBalance -= entry.Amount
}
// If this is a new incoming (un-committed)
// HTLC, then we need to update their balance
// accordingly by subtracting the amount of
// the HTLC that are funds pending.
// Similarly, we need to debit our balance if
// this is an out going HTLC to reflect the
// pending balance.
balanceDeltas.ModifyForParty(
party,
func(acc int64) int64 {
return acc - int64(entry.Amount)
},
)
}
}

Expand Down Expand Up @@ -2957,7 +2948,7 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView, ourBalance,
},
)

return newView, uncommittedUpdates, nil
return newView, uncommittedUpdates, balanceDeltas, nil
}

// fetchParent is a helper that looks up update log parent entries in the
Expand Down Expand Up @@ -4354,12 +4345,26 @@ func (lc *LightningChannel) computeView(view *HtlcView,
// channel constraints to the final commitment state. If any fee
// updates are found in the logs, the commitment fee rate should be
// changed, so we'll also set the feePerKw to this new value.
filteredHTLCView, uncommitted, err := lc.evaluateHTLCView(
view, &ourBalance, &theirBalance, nextHeight, whoseCommitChain,
filteredHTLCView, uncommitted, deltas, err := lc.evaluateHTLCView(
view, whoseCommitChain, nextHeight,
)
if err != nil {
return 0, 0, 0, nil, err
}

// Add the balance deltas to the balances we got from the commitment
// state.
if deltas.Local >= 0 {
ourBalance += lnwire.MilliSatoshi(deltas.Local)
} else {
ourBalance -= lnwire.MilliSatoshi(-1 * deltas.Local)
}
if deltas.Remote >= 0 {
theirBalance += lnwire.MilliSatoshi(deltas.Remote)
} else {
theirBalance -= lnwire.MilliSatoshi(-1 * deltas.Remote)
}

if updateState {
state := lc.channelState
received := &state.TotalMSatReceived
Expand Down
14 changes: 5 additions & 9 deletions lnwallet/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8781,18 +8781,14 @@ func TestEvaluateView(t *testing.T) {
}

var (
// Create vars to store balance changes. We do
// not check these values in this test because
// balance modification happens on the htlc
// processing level.
ourBalance lnwire.MilliSatoshi
theirBalance lnwire.MilliSatoshi
)

// Evaluate the htlc view, mutate as test expects.
result, uncommitted, err := lc.evaluateHTLCView(
view, &ourBalance, &theirBalance, nextHeight,
test.whoseCommitChain,
// We do not check the balance deltas in this test
// because balance modification happens on the htlc
// processing level.
result, uncommitted, _, err := lc.evaluateHTLCView(
view, test.whoseCommitChain, nextHeight,
)

if err != nil {
Expand Down

0 comments on commit 1a3d207

Please sign in to comment.