From 12136a97a905ab57e9de4a8c6a1c5662af2513f4 Mon Sep 17 00:00:00 2001 From: carla Date: Fri, 23 Apr 2021 08:39:45 +0200 Subject: [PATCH] routing/test: add test for stuck payment with in-flight htlcs Add an additional stuck-payment case, where our payment gets a terminal error while it has other htlcs in-flight, and a shard fails with ErrTerminalPayment. This payment also falls in our class of expected errors, but is not currently handled. The mock is updated accordingly, using the same ordering as in our real RegisterAttempt implementation. --- routing/mock_test.go | 4 +++ routing/payment_lifecycle_test.go | 50 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/routing/mock_test.go b/routing/mock_test.go index cf828baf..0d0b7a5b 100644 --- a/routing/mock_test.go +++ b/routing/mock_test.go @@ -333,6 +333,10 @@ func (m *mockControlTower) RegisterAttempt(phash lntypes.Hash, return channeldb.ErrPaymentAlreadyFailed } + if settled || failed { + return channeldb.ErrPaymentTerminal + } + // Add attempt to payment. p.attempts = append(p.attempts, channeldb.HTLCAttempt{ HTLCAttemptInfo: *a, diff --git a/routing/payment_lifecycle_test.go b/routing/payment_lifecycle_test.go index e8aa8c51..01383d21 100644 --- a/routing/payment_lifecycle_test.go +++ b/routing/payment_lifecycle_test.go @@ -650,6 +650,56 @@ func TestRouterPaymentStateMachine(t *testing.T) { }, paymentErr: channeldb.ErrPaymentAlreadyFailed, }, + { + // A MP payment scenario when our path finding returns + // after we've just received a terminal failure, and + // we have another shard still in flight. + name: "MP shard in flight after terminal", + + steps: []string{ + routerInitPayment, + + // shard 0 + routeRelease, + routerRegisterAttempt, + sendToSwitchSuccess, + + // shard 1 + routeRelease, + routerRegisterAttempt, + sendToSwitchSuccess, + + // shard 2 + routeRelease, + routerRegisterAttempt, + sendToSwitchSuccess, + + // We find a path for another shard. + routeRelease, + + // shard 0 fails with a terminal error. + getPaymentResultTerminalFailure, + routerFailAttempt, + routerFailPayment, + + // We try to register our final shard after + // processing a terminal failure. + routerRegisterAttempt, + + // Our in-flight shards fail. + getPaymentResultTempFailure, + getPaymentResultTempFailure, + routerFailAttempt, + routerFailAttempt, + + // Payment fails. + paymentError, + }, + routes: []*route.Route{ + shard, shard, shard, shard, + }, + paymentErr: channeldb.ErrPaymentTerminal, + }, } for _, test := range tests {