Skip to content

Commit

Permalink
multi: use more efficient key to avoid hashing the blob.
Browse files Browse the repository at this point in the history
Moreover introduce a new function which returns all HTLCs not just
the ones which are active on both htlcs.
  • Loading branch information
ziggie1984 committed Oct 29, 2024
1 parent e488002 commit fbaf2dc
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 9 deletions.
64 changes: 57 additions & 7 deletions channeldb/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2472,15 +2472,18 @@ func (c *OpenChannel) ActiveHtlcs() []HTLC {

// We'll only return HTLC's that are locked into *both* commitment
// transactions. So we'll iterate through their set of HTLC's to note
// which ones are present on their commitment.
remoteHtlcs := make(map[[32]byte]struct{})
// which ones are present on their commitment. We combine the RHash and
// the HTLC index to create a unique key.
remoteHtlcs := make(map[[32 + 8]byte]struct{})
var htlcKey [32 + 8]byte
for _, htlc := range c.RemoteCommitment.Htlcs {
log.Tracef("RemoteCommitment has htlc: id=%v, update=%v "+
"incoming=%v", htlc.HtlcIndex, htlc.LogIndex,
htlc.Incoming)

onionHash := sha256.Sum256(htlc.OnionBlob[:])
remoteHtlcs[onionHash] = struct{}{}
copy(htlcKey[:32], htlc.RHash[:])
binary.BigEndian.PutUint64(htlcKey[32:], htlc.HtlcIndex)
remoteHtlcs[htlcKey] = struct{}{}
}

// Now that we know which HTLC's they have, we'll only mark the HTLC's
Expand All @@ -2491,9 +2494,10 @@ func (c *OpenChannel) ActiveHtlcs() []HTLC {
"incoming=%v", htlc.HtlcIndex, htlc.LogIndex,
htlc.Incoming)

onionHash := sha256.Sum256(htlc.OnionBlob[:])
if _, ok := remoteHtlcs[onionHash]; !ok {
log.Tracef("Skipped htlc due to onion mismatched: "+
copy(htlcKey[:32], htlc.RHash[:])
binary.BigEndian.PutUint64(htlcKey[32:], htlc.HtlcIndex)
if _, ok := remoteHtlcs[htlcKey]; !ok {
log.Tracef("Skipped htlc due to htlcKey mismatch: "+
"id=%v, update=%v incoming=%v",
htlc.HtlcIndex, htlc.LogIndex, htlc.Incoming)

Expand All @@ -2506,6 +2510,52 @@ func (c *OpenChannel) ActiveHtlcs() []HTLC {
return activeHtlcs
}

// LocalAndRemoteHtlcs returns a slice of HTLC's which are currently active on
// both or on either commitment transactions.
func (c *OpenChannel) LocalAndRemoteHtlcs() []HTLC {
c.RLock()
defer c.RUnlock()

activeHtlcs := make([]HTLC, 0, len(c.RemoteCommitment.Htlcs))

// We'll only return HTLC's that are locked into *both* commitment
// transactions. So we'll iterate through their set of HTLC's to note
// which ones are present on their commitment. We combine the RHash and
// the HTLC index to create a unique key.
remoteHtlcs := make(map[[32 + 8]byte]struct{})
var htlcKey [32 + 8]byte
for _, htlc := range c.RemoteCommitment.Htlcs {
log.Tracef("RemoteCommitment has htlc: id=%v, update=%v "+
"incoming=%v", htlc.HtlcIndex, htlc.LogIndex,
htlc.Incoming)

copy(htlcKey[:32], htlc.RHash[:])
binary.BigEndian.PutUint64(htlcKey[32:], htlc.HtlcIndex)
remoteHtlcs[htlcKey] = struct{}{}
activeHtlcs = append(activeHtlcs, htlc)
}

// Now that we know which HTLC's they have, we'll only mark the HTLC's
// as active if *we* know them as well.
for _, htlc := range c.LocalCommitment.Htlcs {
log.Tracef("LocalCommitment has htlc: id=%v, update=%v "+
"incoming=%v", htlc.HtlcIndex, htlc.LogIndex,
htlc.Incoming)

copy(htlcKey[:32], htlc.RHash[:])
binary.BigEndian.PutUint64(htlcKey[32:], htlc.HtlcIndex)
// We skip the htlcs which are already part of the remote set to
// not have duplicates.
if _, ok := remoteHtlcs[htlcKey]; ok {
continue
}

activeHtlcs = append(activeHtlcs, htlc)
}

return activeHtlcs
}

// HTLC is the on-disk representation of a hash time-locked contract. HTLCs are
// contained within ChannelDeltas which encode the current state of the
// commitment between state updates.
Expand Down
2 changes: 1 addition & 1 deletion lnwallet/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -5403,7 +5403,7 @@ func (lc *LightningChannel) IsChannelClean() bool {

// We call ActiveHtlcs to ensure there are no HTLCs on either
// commitment.
if len(lc.channelState.ActiveHtlcs()) != 0 {
if len(lc.channelState.LocalAndRemoteHtlcs()) != 0 {
return false
}

Expand Down
2 changes: 1 addition & 1 deletion rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2811,7 +2811,7 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
// If the user hasn't specified NoWait, then before we attempt
// to close the channel we ensure there are no active HTLCs on
// the link.
if !in.NoWait && len(channel.ActiveHtlcs()) != 0 {
if !in.NoWait && len(channel.LocalAndRemoteHtlcs()) != 0 {
return fmt.Errorf("cannot co-op close channel " +
"with active htlcs")
}
Expand Down

0 comments on commit fbaf2dc

Please sign in to comment.