Open matheusd opened 10 months ago
So all the balance is on the side of Alice? I would expect Bob to mark the channel as fully resolved once it sees the force close transaction to confirm and no balance being on Bob's end. Are you sure it's not just a timing issue? E.g. if you wait a couple of hundred milliseconds after mining the blocks, does the channel not go away? Or maybe it goes away once Alice successfully sweeps their time locked output?
Hmm, looks like it indeed depends on Bob's output being big enough to be fully recovered on the sweep. Going to make a a few different tests and see if I reproduce the issue I see in the field.
On the following scenario:
Bob ends up with a
pending_force_close
channel with negativeblocks_til_maturity
that never resolves itself automatically.How should such channels be handled?
Some options:
NOTE: Bob finds the on-chain funds correctly in this case, the issue is the extraneous entry in the pending_foce_close list.
Example itest that demonstrates issue
```go package itest import ( "github.com/btcsuite/btcd/btcutil" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest" ) func testRestoreWithSCBAfterLongForceClosed(ht *lntest.HarnessTest) { chanAmt := btcutil.Amount(100000) alice := ht.Alice // Create bob and track seed. password := []byte("El Psy Kongroo") bob, mnemonic, _ := ht.NewNodeWithSeed( "dave", nil, password, false, ) ht.EnsureConnected(alice, bob) // Open alice <> bob channel. cp := ht.OpenChannel( alice, bob, lntest.OpenChannelParams{Amt: chanAmt}, ) // Advance channel state. const paymentAmt = 1000 payReqs, _, _ := ht.CreatePayReqs(bob, paymentAmt, 1) ht.CompletePaymentRequests(alice, payReqs) // Save bob's backup. chanBackup := bob.RPC.ExportAllChanBackups() // Bob goes offline. ht.Shutdown(bob) // Alice force-closes the channel while Bob is offline. ht.ForceCloseChannel(alice, cp) // Mine a few blocks for good measure. ht.MineBlocks(64) // Bob restores its node from seed, applying the SCB. backupSnapshot := &lnrpc.ChanBackupSnapshot{ MultiChanBackup: chanBackup.MultiChanBackup, } bob2 := ht.RestoreNodeWithSeed("bob2", nil, password, mnemonic, "", revocationWindow, backupSnapshot) // Mine a few blocks for good measure. ht.MineBlocks(64) // Channel was closed long ago, how to handle the pending force close // channel? resp := bob2.RPC.PendingChannels() ht.Logf(spew.Sdump(resp)) ht.AssertNumPendingForceClose(bob, 0) // This fails. } ```