mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 09:48:19 +01:00
lnwallet: add new modified HTLC index to the updateLog
In this commit, we add a new index to the HTLC log. This new index is meant to ensure that we don't attempt to modify and HTLC twice. An HTLC modification is either a fail or a settle. This is the first in a series of commits to fix an existing bug in the state machine that can cause a panic if a remote node attempts to settle an HTLC twice.
This commit is contained in:
parent
19e826cada
commit
56ebd6de8d
1 changed files with 29 additions and 8 deletions
|
@ -825,7 +825,7 @@ func (lc *LightningChannel) extractPayDescs(commitHeight uint64,
|
||||||
return incomingHtlcs, outgoingHtlcs, nil
|
return incomingHtlcs, outgoingHtlcs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// diskCommitToMemCommit converts tthe on-disk commitment format to our
|
// diskCommitToMemCommit converts the on-disk commitment format to our
|
||||||
// in-memory commitment format which is needed in order to properly resume
|
// in-memory commitment format which is needed in order to properly resume
|
||||||
// channel operations after a restart.
|
// channel operations after a restart.
|
||||||
func (lc *LightningChannel) diskCommitToMemCommit(isLocal, isPendingCommit bool,
|
func (lc *LightningChannel) diskCommitToMemCommit(isLocal, isPendingCommit bool,
|
||||||
|
@ -1090,16 +1090,22 @@ type updateLog struct {
|
||||||
// offerIndex is an index that maps the counter for offered HTLC's to
|
// offerIndex is an index that maps the counter for offered HTLC's to
|
||||||
// their list element within the main list.List.
|
// their list element within the main list.List.
|
||||||
htlcIndex map[uint64]*list.Element
|
htlcIndex map[uint64]*list.Element
|
||||||
|
|
||||||
|
// modifiedHtlcs is a set that keeps track of all the current modified
|
||||||
|
// htlcs. A modified HTLC is one that's present in the log, and has as
|
||||||
|
// a pending fail or settle that's attempting to consume it.
|
||||||
|
modifiedHtlcs map[uint64]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// newUpdateLog creates a new updateLog instance.
|
// newUpdateLog creates a new updateLog instance.
|
||||||
func newUpdateLog(logIndex, htlcCounter uint64) *updateLog {
|
func newUpdateLog(logIndex, htlcCounter uint64) *updateLog {
|
||||||
return &updateLog{
|
return &updateLog{
|
||||||
List: list.New(),
|
List: list.New(),
|
||||||
updateIndex: make(map[uint64]*list.Element),
|
updateIndex: make(map[uint64]*list.Element),
|
||||||
htlcIndex: make(map[uint64]*list.Element),
|
htlcIndex: make(map[uint64]*list.Element),
|
||||||
logIndex: logIndex,
|
logIndex: logIndex,
|
||||||
htlcCounter: htlcCounter,
|
htlcCounter: htlcCounter,
|
||||||
|
modifiedHtlcs: make(map[uint64]struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1158,6 +1164,19 @@ func (u *updateLog) removeHtlc(i uint64) {
|
||||||
entry := u.htlcIndex[i]
|
entry := u.htlcIndex[i]
|
||||||
u.Remove(entry)
|
u.Remove(entry)
|
||||||
delete(u.htlcIndex, i)
|
delete(u.htlcIndex, i)
|
||||||
|
|
||||||
|
// htlcHasModification returns true if the HTLC identified by the passed index
|
||||||
|
// has a pending modification within the log.
|
||||||
|
func (u *updateLog) htlcHasModification(i uint64) bool {
|
||||||
|
_, o := u.modifiedHtlcs[i]
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// markHtlcModified marks an HTLC as modified based on its HTLC index. After a
|
||||||
|
// call to this method, htlcHasModification will return true until the HTLC is
|
||||||
|
// removed.
|
||||||
|
func (u *updateLog) markHtlcModified(i uint64) {
|
||||||
|
u.modifiedHtlcs[i] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compactLogs performs garbage collection within the log removing HTLCs which
|
// compactLogs performs garbage collection within the log removing HTLCs which
|
||||||
|
@ -1509,10 +1528,12 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
|
||||||
if !isDustRemote {
|
if !isDustRemote {
|
||||||
theirP2WSH, theirWitnessScript, err := genHtlcScript(
|
theirP2WSH, theirWitnessScript, err := genHtlcScript(
|
||||||
false, false, wireMsg.Expiry, wireMsg.PaymentHash,
|
false, false, wireMsg.Expiry, wireMsg.PaymentHash,
|
||||||
remoteCommitKeys)
|
remoteCommitKeys,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pd.theirPkScript = theirP2WSH
|
pd.theirPkScript = theirP2WSH
|
||||||
pd.theirWitnessScript = theirWitnessScript
|
pd.theirWitnessScript = theirWitnessScript
|
||||||
}
|
}
|
||||||
|
@ -1571,7 +1592,7 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreCommitState will restore the local commitment chain and updateLog
|
// restoreCommitState will restore the local commitment chain and updateLog
|
||||||
// state to a consistent in-memory representation of the passed dis commitment.
|
// state to a consistent in-memory representation of the passed disk commitment.
|
||||||
// This method is to be used upon reconnection to our channel counter party.
|
// This method is to be used upon reconnection to our channel counter party.
|
||||||
// Once the connection has been established, we'll prepare our in memory state
|
// Once the connection has been established, we'll prepare our in memory state
|
||||||
// to re-sync states with the remote party, and also verify/extend new proposed
|
// to re-sync states with the remote party, and also verify/extend new proposed
|
||||||
|
|
Loading…
Add table
Reference in a new issue