Merge branch '0-18-4-branch-rc2-9324' into 0-18-4-branch-rc2

This commit is contained in:
Oliver Gugger 2024-12-05 21:41:27 +01:00
commit f5ad1ee438
No known key found for this signature in database
GPG Key ID: 8E4256593F177720
3 changed files with 56 additions and 12 deletions

View File

@ -482,6 +482,20 @@ func (c *ChannelArbitrator) Start(state *chanArbStartState) error {
return err return err
} }
c.wg.Add(1)
go c.channelAttendant(bestHeight, state.commitSet)
return nil
}
// progressStateMachineAfterRestart attempts to progress the state machine
// after a restart. This makes sure that if the state transition failed, we
// will try to progress the state machine again. Moreover it will relaunch
// resolvers if the channel is still in the pending close state and has not
// been fully resolved yet.
func (c *ChannelArbitrator) progressStateMachineAfterRestart(bestHeight int32,
commitSet *CommitSet) error {
// If the channel has been marked pending close in the database, and we // If the channel has been marked pending close in the database, and we
// haven't transitioned the state machine to StateContractClosed (or a // haven't transitioned the state machine to StateContractClosed (or a
// succeeding state), then a state transition most likely failed. We'll // succeeding state), then a state transition most likely failed. We'll
@ -527,7 +541,7 @@ func (c *ChannelArbitrator) Start(state *chanArbStartState) error {
// on-chain state, and our set of active contracts. // on-chain state, and our set of active contracts.
startingState := c.state startingState := c.state
nextState, _, err := c.advanceState( nextState, _, err := c.advanceState(
triggerHeight, trigger, state.commitSet, triggerHeight, trigger, commitSet,
) )
if err != nil { if err != nil {
switch err { switch err {
@ -564,14 +578,12 @@ func (c *ChannelArbitrator) Start(state *chanArbStartState) error {
// receive a chain event from the chain watcher that the // receive a chain event from the chain watcher that the
// commitment has been confirmed on chain, and before we // commitment has been confirmed on chain, and before we
// advance our state step, we call InsertConfirmedCommitSet. // advance our state step, we call InsertConfirmedCommitSet.
err := c.relaunchResolvers(state.commitSet, triggerHeight) err := c.relaunchResolvers(commitSet, triggerHeight)
if err != nil { if err != nil {
return err return err
} }
} }
c.wg.Add(1)
go c.channelAttendant(bestHeight)
return nil return nil
} }
@ -2775,13 +2787,28 @@ func (c *ChannelArbitrator) updateActiveHTLCs() {
// Nursery for incubation, and ultimate sweeping. // Nursery for incubation, and ultimate sweeping.
// //
// NOTE: This MUST be run as a goroutine. // NOTE: This MUST be run as a goroutine.
func (c *ChannelArbitrator) channelAttendant(bestHeight int32) { //
//nolint:funlen
func (c *ChannelArbitrator) channelAttendant(bestHeight int32,
commitSet *CommitSet) {
// TODO(roasbeef): tell top chain arb we're done // TODO(roasbeef): tell top chain arb we're done
defer func() { defer func() {
c.wg.Done() c.wg.Done()
}() }()
err := c.progressStateMachineAfterRestart(bestHeight, commitSet)
if err != nil {
// In case of an error, we return early but we do not shutdown
// LND, because there might be other channels that still can be
// resolved and we don't want to interfere with that.
// We continue to run the channel attendant in case the channel
// closes via other means for example the remote pary force
// closes the channel. So we log the error and continue.
log.Errorf("Unable to progress state machine after "+
"restart: %v", err)
}
for { for {
select { select {

View File

@ -21,6 +21,7 @@ import (
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lntest/mock" "github.com/lightningnetwork/lnd/lntest/mock"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@ -1043,10 +1044,19 @@ func TestChannelArbitratorLocalForceClosePendingHtlc(t *testing.T) {
// Post restart, it should be the case that our resolver was properly // Post restart, it should be the case that our resolver was properly
// supplemented, and we only have a single resolver in the final set. // supplemented, and we only have a single resolver in the final set.
if len(chanArb.activeResolvers) != 1 { // The resolvers are added concurrently so we need to wait here.
t.Fatalf("expected single resolver, instead got: %v", err = wait.NoError(func() error {
len(chanArb.activeResolvers)) chanArb.activeResolversLock.Lock()
} defer chanArb.activeResolversLock.Unlock()
if len(chanArb.activeResolvers) != 1 {
return fmt.Errorf("expected single resolver, instead "+
"got: %v", len(chanArb.activeResolvers))
}
return nil
}, defaultTimeout)
require.NoError(t, err)
// We'll now examine the in-memory state of the active resolvers to // We'll now examine the in-memory state of the active resolvers to
// ensure t hey were populated properly. // ensure t hey were populated properly.
@ -2884,9 +2894,12 @@ func TestChannelArbitratorStartForceCloseFail(t *testing.T) {
{ {
name: "Commitment is rejected with an " + name: "Commitment is rejected with an " +
"unmatched error", "unmatched error",
broadcastErr: fmt.Errorf("Reject Commitment Tx"), broadcastErr: fmt.Errorf("Reject Commitment Tx"),
expectedState: StateBroadcastCommit, expectedState: StateBroadcastCommit,
expectedStartup: false, // We should still be able to start up since we other
// channels might be closing as well and we should
// resolve the contracts.
expectedStartup: true,
}, },
// We started after the DLP was triggered, and try to force // We started after the DLP was triggered, and try to force

View File

@ -26,6 +26,10 @@
* [Make the contract resolutions for the channel arbitrator optional]( * [Make the contract resolutions for the channel arbitrator optional](
https://github.com/lightningnetwork/lnd/pull/9253). https://github.com/lightningnetwork/lnd/pull/9253).
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/9324) to prevent
potential deadlocks when LND depends on external components (e.g. aux
components, hooks).
# New Features # New Features
The main channel state machine and database now allow for processing and storing The main channel state machine and database now allow for processing and storing