Skip to content

Commit

Permalink
lnwallet: fix HTLC mutation bug in commitment chain
Browse files Browse the repository at this point in the history
This commit fixes a class of bug that can arise in the channel state
machine when a very high throughput workflow is attempted. Since the
PaymentDescriptor’s within a commitment pointed directly into the log,
any changes to a payment descriptor would also be reflected in all
other ones. Due to this mutation possibility, at times, the
locateOutputIndex method would fail since the HTLC’s pkScript was
modified, causing the channel to fail.

We fix this class of bug by simply ensure that once an HTLC has been
associated with a particular commitment, then it becomes immutable.
  • Loading branch information
Roasbeef committed Apr 12, 2017
1 parent eca3a10 commit a3fd738
Showing 1 changed file with 18 additions and 7 deletions.
25 changes: 18 additions & 7 deletions lnwallet/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ type commitment struct {

// htlcs is the set of HTLCs which remain unsettled within this
// commitment.
outgoingHTLCs []*PaymentDescriptor
incomingHTLCs []*PaymentDescriptor
outgoingHTLCs []PaymentDescriptor
incomingHTLCs []PaymentDescriptor
}

// toChannelDelta converts the target commitment into a format suitable to be
Expand Down Expand Up @@ -1302,17 +1302,28 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
// ordering. This lets us skip sending the entire transaction over,
// instead we'll just send signatures.
txsort.InPlaceSort(commitTx)

return &commitment{
c := &commitment{
txn: commitTx,
height: nextHeight,
ourBalance: ourBalance,
ourMessageIndex: ourLogIndex,
theirMessageIndex: theirLogIndex,
theirBalance: theirBalance,
outgoingHTLCs: filteredHTLCView.ourUpdates,
incomingHTLCs: filteredHTLCView.theirUpdates,
}, nil
}

// In order to ensure _none_ of the HTLC's associated with this new
// commitment are mutated, we'll manually copy over each HTLC to its
// respective slice.
c.outgoingHTLCs = make([]PaymentDescriptor, len(filteredHTLCView.ourUpdates))
for i, htlc := range filteredHTLCView.ourUpdates {
c.outgoingHTLCs[i] = *htlc
}
c.incomingHTLCs = make([]PaymentDescriptor, len(filteredHTLCView.theirUpdates))
for i, htlc := range filteredHTLCView.theirUpdates {
c.incomingHTLCs[i] = *htlc
}

return c, nil
}

// evaluateHTLCView processes all update entries in both HTLC update logs,
Expand Down

0 comments on commit a3fd738

Please sign in to comment.