contractcourt+switch: keep channels with timed-out initiated htlcs.

This commit enables the user to specify he is not interested in
automatically close channels with pending payments that their
corresponding htlcs have timed-out.
By requiring a configurable grace period uptime of our node
before closing such channels, we give a chance to the other node to
properly cancel the htlc and avoid unnecessary on-chain transaction.
In mobile it is very important for the user experience as otherwise
channels will be force closed more frequently.
This commit is contained in:
Roei Erez
2020-02-03 12:52:22 +02:00
parent f8da26ee30
commit 0407b37fce
9 changed files with 196 additions and 28 deletions

View File

@@ -15,6 +15,7 @@ import (
"github.com/coreos/bbolt"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
@@ -309,6 +310,12 @@ func createTestChannelArbitrator(t *testing.T, log ArbitratorLog) (*chanArbTestC
return nil
},
OnionProcessor: &mockOnionProcessor{},
IsForwardedHTLC: func(chanID lnwire.ShortChannelID,
htlcIndex uint64) bool {
return true
},
Clock: clock.NewDefaultClock(),
}
// We'll use the resolvedChan to synchronize on call to
@@ -1811,3 +1818,87 @@ func TestChannelArbitratorDanglingCommitForceClose(t *testing.T) {
})
}
}
// TestChannelArbitratorPendingExpiredHTLC tests that if we have pending htlc
// that is expired we will only go to chain if we are running at least the
// time defined in PaymentsExpirationGracePeriod.
// During this time the remote party is expected to send his updates and cancel
// The htlc.
func TestChannelArbitratorPendingExpiredHTLC(t *testing.T) {
t.Parallel()
// We'll create the arbitrator and its backing log in a default state.
log := &mockArbitratorLog{
state: StateDefault,
newStates: make(chan ArbitratorState, 5),
resolvers: make(map[ContractResolver]struct{}),
}
chanArbCtx, err := createTestChannelArbitrator(t, log)
if err != nil {
t.Fatalf("unable to create ChannelArbitrator: %v", err)
}
chanArb := chanArbCtx.chanArb
// We'll inject a test clock implementation so we can control the uptime.
startTime := time.Date(2020, time.February, 3, 13, 0, 0, 0, time.UTC)
testClock := clock.NewTestClock(startTime)
chanArb.cfg.Clock = testClock
// We also configure the grace period and the IsForwardedHTLC to identify
// the htlc as our initiated payment.
chanArb.cfg.PaymentsExpirationGracePeriod = time.Second * 15
chanArb.cfg.IsForwardedHTLC = func(chanID lnwire.ShortChannelID,
htlcIndex uint64) bool {
return false
}
if err := chanArb.Start(); err != nil {
t.Fatalf("unable to start ChannelArbitrator: %v", err)
}
defer func() {
if err := chanArb.Stop(); err != nil {
t.Fatalf("unable to stop chan arb: %v", err)
}
}()
// Now that our channel arb has started, we'll set up
// its contract signals channel so we can send it
// various HTLC updates for this test.
htlcUpdates := make(chan *ContractUpdate)
signals := &ContractSignals{
HtlcUpdates: htlcUpdates,
ShortChanID: lnwire.ShortChannelID{},
}
chanArb.UpdateContractSignals(signals)
// Next, we'll send it a new HTLC that is set to expire
// in 10 blocks.
htlcIndex := uint64(99)
htlcExpiry := uint32(10)
pendingHTLC := channeldb.HTLC{
Incoming: false,
Amt: 10000,
HtlcIndex: htlcIndex,
RefundTimeout: htlcExpiry,
}
htlcUpdates <- &ContractUpdate{
HtlcKey: RemoteHtlcSet,
Htlcs: []channeldb.HTLC{pendingHTLC},
}
// We will advance the uptime to 10 seconds which should be still within
// the grace period and should not trigger going to chain.
testClock.SetTime(startTime.Add(time.Second * 10))
chanArbCtx.blockEpochs <- &chainntnfs.BlockEpoch{Height: 5}
chanArbCtx.AssertState(StateDefault)
// We will advance the uptime to 16 seconds which should trigger going
// to chain.
testClock.SetTime(startTime.Add(time.Second * 16))
chanArbCtx.blockEpochs <- &chainntnfs.BlockEpoch{Height: 6}
chanArbCtx.AssertStateTransitions(
StateBroadcastCommit,
StateCommitmentBroadcasted,
)
}