Skip to content

Commit e8875e0

Browse files
authored
Merge pull request #9602 from lightningnetwork/yy-pending-remote-commit
multi: make sure HTLCs are locked in the itest
2 parents 09b6745 + 3b7f9e1 commit e8875e0

15 files changed

+2876
-2777
lines changed

contractcourt/chain_watcher.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,35 @@ func (c *CommitSet) toActiveHTLCSets() map[HtlcSetKey]htlcSet {
131131
return htlcSets
132132
}
133133

134+
// String return a human-readable representation of the CommitSet.
135+
func (c *CommitSet) String() string {
136+
if c == nil {
137+
return "nil"
138+
}
139+
140+
// Create a descriptive string for the ConfCommitKey.
141+
commitKey := "none"
142+
c.ConfCommitKey.WhenSome(func(k HtlcSetKey) {
143+
commitKey = k.String()
144+
})
145+
146+
// Create a map to hold all the htlcs.
147+
htlcSet := make(map[string]string)
148+
for k, htlcs := range c.HtlcSets {
149+
// Create a map for this particular set.
150+
desc := make([]string, len(htlcs))
151+
for i, htlc := range htlcs {
152+
desc[i] = fmt.Sprintf("%x", htlc.RHash)
153+
}
154+
155+
// Add the description to the set key.
156+
htlcSet[k.String()] = fmt.Sprintf("count: %v, htlcs=%v",
157+
len(htlcs), desc)
158+
}
159+
160+
return fmt.Sprintf("ConfCommitKey=%v, HtlcSets=%v", commitKey, htlcSet)
161+
}
162+
134163
// ChainEventSubscription is a struct that houses a subscription to be notified
135164
// for any on-chain events related to a channel. There are three types of
136165
// possible on-chain events: a cooperative channel closure, a unilateral

contractcourt/channel_arbitrator.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -947,9 +947,9 @@ func (c *ChannelArbitrator) stateStep(
947947
// If we're in the default state, then we'll check our set of actions
948948
// to see if while we were down, conditions have changed.
949949
case StateDefault:
950-
log.Debugf("ChannelArbitrator(%v): new block (height=%v) "+
951-
"examining active HTLC's", c.cfg.ChanPoint,
952-
triggerHeight)
950+
log.Debugf("ChannelArbitrator(%v): examining active HTLCs in "+
951+
"block %v, confCommitSet: %v", c.cfg.ChanPoint,
952+
triggerHeight, lnutils.LogClosure(confCommitSet.String))
953953

954954
// As a new block has been connected to the end of the main
955955
// chain, we'll check to see if we need to make any on-chain
@@ -2155,6 +2155,20 @@ func (c *ChannelArbitrator) checkRemoteDanglingActions(
21552155
continue
21562156
}
21572157

2158+
preimageAvailable, err := c.isPreimageAvailable(htlc.RHash)
2159+
if err != nil {
2160+
log.Errorf("ChannelArbitrator(%v): failed to query "+
2161+
"preimage for dangling htlc=%x from remote "+
2162+
"commitments diff", c.cfg.ChanPoint,
2163+
htlc.RHash[:])
2164+
2165+
continue
2166+
}
2167+
2168+
if preimageAvailable {
2169+
continue
2170+
}
2171+
21582172
// Dust htlcs can be canceled back even before the commitment
21592173
// transaction confirms. Dust htlcs are not enforceable onchain.
21602174
// If another version of the commit tx would confirm we either
@@ -2824,7 +2838,8 @@ func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
28242838
case beat := <-c.BlockbeatChan:
28252839
bestHeight = beat.Height()
28262840

2827-
log.Debugf("ChannelArbitrator(%v): new block height=%v",
2841+
log.Debugf("ChannelArbitrator(%v): received new "+
2842+
"block: height=%v, processing...",
28282843
c.cfg.ChanPoint, bestHeight)
28292844

28302845
err := c.handleBlockbeat(beat)

docs/release-notes/release-notes-0.19.0.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ close transaction.
246246
* `lncli abandonchannel` (`Lightning.AbandonChannel` RPC)
247247
* `lncli restorechanbackup` (`Lightning.RestoreChannelBackups` RPC)
248248
* `lncli verifychanbackup` (`Lightning.VerifyChanBackup` RPC)
249+
249250
* The `ForwardInterceptor`'s `MODIFY` option will
250251
[merge](https://github.com/lightningnetwork/lnd/pull/9240) any custom
251252
range TLVs provided with the existing set of records on the HTLC,
@@ -255,6 +256,11 @@ close transaction.
255256
`ProofMatureDelta` used in gossip to be configurable via
256257
`--gossip.announcement-conf`, with a default value of 6.
257258

259+
* [Added a boolean field
260+
`LockedIn`](https://github.com/lightningnetwork/lnd/pull/9602) in
261+
`lnrpc.HTLC`. This field is used to indicate whether a given HTLC has been
262+
locked in by the remote peer.
263+
258264
## lncli Updates
259265

260266
* [Fixed](https://github.com/lightningnetwork/lnd/pull/9605) a case where

htlcswitch/link.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,11 @@ loop:
15821582
select {
15831583
case item := <-l.hodlQueue.ChanOut():
15841584
htlcResolution = item.(invoices.HtlcResolution)
1585+
1586+
// No need to process it if the link is broken.
1587+
case <-l.cg.Done():
1588+
return ErrLinkShuttingDown
1589+
15851590
default:
15861591
break loop
15871592
}
@@ -2052,6 +2057,9 @@ func (l *channelLink) cleanupSpuriousResponse(pkt *htlcPacket) {
20522057
func (l *channelLink) handleUpstreamMsg(ctx context.Context,
20532058
msg lnwire.Message) {
20542059

2060+
l.log.Tracef("receive upstream msg %v, handling now... ", msg.MsgType())
2061+
defer l.log.Tracef("handled upstream msg %v", msg.MsgType())
2062+
20552063
// First check if the message is an update and we are capable of
20562064
// receiving updates right now.
20572065
if msg.MsgType().IsChannelUpdate() && !l.quiescer.CanRecvUpdates() {

htlcswitch/switch.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,6 +2243,9 @@ func (s *Switch) getLinkByMapping(pkt *htlcPacket) (ChannelLink, error) {
22432243
chanID := pkt.outgoingChanID
22442244
aliasID := s.cfg.IsAlias(chanID)
22452245

2246+
log.Debugf("Querying outgoing link using chanID=%v, aliasID=%v", chanID,
2247+
aliasID)
2248+
22462249
// Set the originalOutgoingChanID so the proper channel_update can be
22472250
// sent back if the option-scid-alias feature bit was negotiated.
22482251
pkt.originalOutgoingChanID = chanID
@@ -2299,6 +2302,9 @@ func (s *Switch) getLinkByMapping(pkt *htlcPacket) (ChannelLink, error) {
22992302
// forward over it and this is a channel where the option-scid-alias
23002303
// feature bit was negotiated.
23012304
if link.IsUnadvertised() {
2305+
log.Debugf("Link is unadvertised, chanID=%v, baseScid=%v",
2306+
chanID, baseScid)
2307+
23022308
return nil, ErrChannelLinkNotFound
23032309
}
23042310

itest/flakes.go

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package itest
22

33
import (
4-
"runtime"
54
"time"
65

76
"github.com/btcsuite/btcd/btcutil"
@@ -72,39 +71,6 @@ func flakeTxNotifierNeutrino(ht *lntest.HarnessTest) {
7271
}
7372
}
7473

75-
// flakeSkipPendingSweepsCheckDarwin documents a flake found only in macOS
76-
// build. When running in macOS, we might see three anchor sweeps - one from the
77-
// local, one from the remote, and one from the pending remote:
78-
// - the local one will be swept.
79-
// - the remote one will be marked as failed due to `testmempoolaccept` check.
80-
// - the pending remote one will not be attempted due to it being uneconomical
81-
// since it was not used for CPFP.
82-
//
83-
// The anchor from the pending remote may or may not appear, which is a bug
84-
// found only in macOS - when updating the commitments, the channel state
85-
// machine somehow thinks we still have a pending remote commitment, causing it
86-
// to sweep the anchor from that version.
87-
//
88-
// TODO(yy): fix the above bug in the channel state machine.
89-
func flakeSkipPendingSweepsCheckDarwin(ht *lntest.HarnessTest,
90-
node *node.HarnessNode, num int) {
91-
92-
// Skip the assertion below if it's on macOS.
93-
if isDarwin() {
94-
ht.Logf("Skipped AssertNumPendingSweeps for node %s",
95-
node.Name())
96-
97-
return
98-
}
99-
100-
ht.AssertNumPendingSweeps(node, num)
101-
}
102-
103-
// isDarwin returns true if the test is running on a macOS.
104-
func isDarwin() bool {
105-
return runtime.GOOS == "darwin"
106-
}
107-
10874
// flakeInconsistentHTLCView documents a flake found that the `ListChannels` RPC
10975
// can give inaccurate HTLC states, which is found when we call
11076
// `AssertHTLCNotActive` after a commitment dance is finished. Suppose Carol is

itest/lnd_multi-hop_force_close_test.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,7 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest,
422422
if ht.IsNeutrinoBackend() {
423423
numSweeps = 2
424424
}
425-
426-
flakeSkipPendingSweepsCheckDarwin(ht, bob, numSweeps)
425+
ht.AssertNumPendingSweeps(bob, numSweeps)
427426

428427
// We expect to see tow txns in the mempool,
429428
// 1. Bob's force close tx.
@@ -744,6 +743,7 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest,
744743

745744
// Stop Bob so he won't be able to settle the incoming htlc.
746745
restartBob := ht.SuspendNode(bob)
746+
ht.AssertPeerNotConnected(carol, bob)
747747

748748
// Settle invoice. This will just mark the invoice as settled, as there
749749
// is no link anymore to remove the htlc from the commitment tx. For
@@ -752,6 +752,9 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest,
752752
// channel arbitrator won't go to chain.
753753
carol.RPC.SettleInvoice(preimage[:])
754754

755+
// Carol should still have one incoming HTLC on channel Bob -> Carol.
756+
ht.AssertNumActiveHtlcs(carol, 1)
757+
755758
// We now advance the block height to the point where Carol will force
756759
// close her channel with Bob, broadcast the closing tx but keep it
757760
// unconfirmed.
@@ -779,8 +782,7 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest,
779782
if ht.IsNeutrinoBackend() {
780783
numSweeps = 2
781784
}
782-
783-
flakeSkipPendingSweepsCheckDarwin(ht, carol, numSweeps)
785+
ht.AssertNumPendingSweeps(carol, numSweeps)
784786

785787
// We expect to see tow txns in the mempool,
786788
// 1. Carol's force close tx.
@@ -1690,6 +1692,7 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest,
16901692

16911693
// Suspend Bob to force Carol to go to chain.
16921694
restartBob := ht.SuspendNode(bob)
1695+
ht.AssertPeerNotConnected(carol, bob)
16931696

16941697
// Settle invoice. This will just mark the invoice as settled, as there
16951698
// is no link anymore to remove the htlc from the commitment tx. For
@@ -1698,6 +1701,9 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest,
16981701
// channel arbitrator won't go to chain.
16991702
carol.RPC.SettleInvoice(preimage[:])
17001703

1704+
// Carol should still have one incoming HTLC on channel Bob -> Carol.
1705+
ht.AssertNumActiveHtlcs(carol, 1)
1706+
17011707
// We now advance the block height to the point where Carol will force
17021708
// close her channel with Bob, broadcast the closing tx but keep it
17031709
// unconfirmed.
@@ -1967,6 +1973,7 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest,
19671973

19681974
// Suspend Bob to force Carol to go to chain.
19691975
restartBob := ht.SuspendNode(bob)
1976+
ht.AssertPeerNotConnected(carol, bob)
19701977

19711978
// Settle invoice. This will just mark the invoice as settled, as there
19721979
// is no link anymore to remove the htlc from the commitment tx. For
@@ -1975,6 +1982,9 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest,
19751982
// channel arbitrator won't go to chain.
19761983
carol.RPC.SettleInvoice(preimage[:])
19771984

1985+
// Carol should still have one incoming HTLC on channel Bob -> Carol.
1986+
ht.AssertNumActiveHtlcs(carol, 1)
1987+
19781988
// We now advance the block height to the point where Carol will force
19791989
// close her channel with Bob, broadcast the closing tx but keep it
19801990
// unconfirmed.
@@ -2307,6 +2317,7 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest,
23072317

23082318
// Suspend bob, so Carol is forced to go on chain.
23092319
restartBob := ht.SuspendNode(bob)
2320+
ht.AssertPeerNotConnected(carol, bob)
23102321

23112322
// Settle invoice. This will just mark the invoice as settled, as there
23122323
// is no link anymore to remove the htlc from the commitment tx. For
@@ -2315,6 +2326,9 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest,
23152326
// channel arbitrator won't go to chain.
23162327
carol.RPC.SettleInvoice(preimage[:])
23172328

2329+
// Carol should still have one incoming HTLC on channel Bob -> Carol.
2330+
ht.AssertNumActiveHtlcs(carol, 1)
2331+
23182332
ht.Logf("Invoice expire height: %d, current: %d", invoiceExpiry,
23192333
ht.CurrentHeight())
23202334

@@ -2334,8 +2348,7 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest,
23342348
if ht.IsNeutrinoBackend() {
23352349
numSweeps = 2
23362350
}
2337-
2338-
flakeSkipPendingSweepsCheckDarwin(ht, carol, numSweeps)
2351+
ht.AssertNumPendingSweeps(carol, numSweeps)
23392352

23402353
// We should see two txns in the mempool, we now a block to confirm,
23412354
// - Carol's force close tx.
@@ -2547,6 +2560,7 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest,
25472560

25482561
// Suspend bob, so Carol is forced to go on chain.
25492562
restartBob := ht.SuspendNode(bob)
2563+
ht.AssertPeerNotConnected(carol, bob)
25502564

25512565
// Settle invoice. This will just mark the invoice as settled, as there
25522566
// is no link anymore to remove the htlc from the commitment tx. For
@@ -2555,6 +2569,9 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest,
25552569
// channel arbitrator won't go to chain.
25562570
carol.RPC.SettleInvoice(preimage[:])
25572571

2572+
// Carol should still have one incoming HTLC on channel Bob -> Carol.
2573+
ht.AssertNumActiveHtlcs(carol, 1)
2574+
25582575
ht.Logf("Invoice expire height: %d, current: %d", invoiceExpiry,
25592576
ht.CurrentHeight())
25602577

@@ -2574,8 +2591,7 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest,
25742591
if ht.IsNeutrinoBackend() {
25752592
numSweeps = 2
25762593
}
2577-
2578-
flakeSkipPendingSweepsCheckDarwin(ht, carol, numSweeps)
2594+
ht.AssertNumPendingSweeps(carol, numSweeps)
25792595

25802596
// We should see two txns in the mempool, we now a block to confirm,
25812597
// - Carol's force close tx.
@@ -2964,6 +2980,7 @@ func runHtlcAggregation(ht *lntest.HarnessTest,
29642980
// close. However, Carol will cancel her invoices to prevent force
29652981
// closes, so we shut her down for now.
29662982
restartCarol := ht.SuspendNode(carol)
2983+
ht.AssertPeerNotConnected(bob, carol)
29672984

29682985
// We'll now mine enough blocks to trigger Bob's broadcast of his
29692986
// commitment transaction due to the fact that the Carol's HTLCs are
@@ -2982,8 +2999,7 @@ func runHtlcAggregation(ht *lntest.HarnessTest,
29822999
if ht.IsNeutrinoBackend() {
29833000
numSweeps = 2
29843001
}
2985-
2986-
flakeSkipPendingSweepsCheckDarwin(ht, bob, numSweeps)
3002+
ht.AssertNumPendingSweeps(bob, numSweeps)
29873003

29883004
// Bob's force close tx and anchor sweeping tx should now be found in
29893005
// the mempool.

itest/lnd_sweep_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,11 @@ func testSweepHTLCs(ht *lntest.HarnessTest) {
11391139
// NOTE: We need to subtract 1 from the deadline as the budget must be
11401140
// used up before the deadline.
11411141
blocksLeft := outgoingHTLCDeadline - outgoingFuncPosition - 1
1142+
1143+
ht.Logf("Bob has incoming sweep tx: %v, outgoing sweep tx: %v, "+
1144+
"blocksLeft=%v, entering fee bumping now...",
1145+
incomingSweep.TxHash(), outgoingSweep.TxHash(), blocksLeft)
1146+
11421147
for i := int32(0); i < blocksLeft; i++ {
11431148
// Mine an empty block.
11441149
ht.MineEmptyBlocks(1)

0 commit comments

Comments
 (0)