itest/test: add test to reproduce settling timed out invoice

Reproduce the case where we allow settling of invoices that have
htlcs that have actually timed out on chain. This bug can rarely
occur if a hodl invoice goes to chain and is manually settled
after it has timed out. Funds are SAFU, but this could be a
headache because the invoice says it's settled when no funds
were claimed.
This commit is contained in:
carla 2021-04-23 08:19:50 +02:00
parent fff6f83f23
commit 16373d3879
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91

@ -5,6 +5,7 @@ import (
"fmt"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntest"
@ -177,6 +178,10 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
err = waitForNumChannelPendingForceClose(ctxt, bob, 0, nil)
require.NoError(t.t, err)
// While we're here, we demonstrate some bugs in our handling of
// invoices that timeout on chain.
assertOnChainInvoiceState(ctxb, t, carol, preimage)
// We'll close out the test by closing the channel from Alice to Bob,
// and then shutting down the new node we created as its no longer
// needed. Coop close, no anchors.
@ -185,3 +190,39 @@ func testMultiHopRemoteForceCloseOnChainHtlcTimeout(net *lntest.NetworkHarness,
ctxt, t, net, alice, aliceChanPoint, false, false,
)
}
// assertOnChainInvoiceState asserts that we have some bugs with how we handle
// hold invoices that are expired on-chain.
// - htlcs accepted: despite being timed out, our htlcs are still in accepted
// state
// - can settle: our invoice that has expired on-chain can still be settled
// even though we don't claim any htlcs.
func assertOnChainInvoiceState(ctx context.Context, t *harnessTest,
node *lntest.HarnessNode, preimage lntypes.Preimage) {
hash := preimage.Hash()
inv, err := node.LookupInvoice(ctx, &lnrpc.PaymentHash{
RHash: hash[:],
})
require.NoError(t.t, err)
for _, htlc := range inv.Htlcs {
require.Equal(t.t, lnrpc.InvoiceHTLCState_ACCEPTED, htlc.State)
}
_, err = node.SettleInvoice(ctx, &invoicesrpc.SettleInvoiceMsg{
Preimage: preimage[:],
})
require.NoError(t.t, err, "expected erroneous invoice settle")
inv, err = node.LookupInvoice(ctx, &lnrpc.PaymentHash{
RHash: hash[:],
})
require.NoError(t.t, err)
require.True(t.t, inv.Settled, "expected erroneously settled invoice")
for _, htlc := range inv.Htlcs {
require.Equal(t.t, lnrpc.InvoiceHTLCState_SETTLED, htlc.State,
"expected htlcs to be erroneously settled")
}
}