lightningd: don't print nasty message when onchaind fails partially-failed HTLC

1. We set an outgoing htlc's `failonion` when we get a commitment_signed.
2. We don't transfer it to the corresponding incoming HTLC until we send
   commitment_signed and receive revoke_and_ack (meaning, outgoing htlc is
   completely dead).
3. If between these steps we go onchain, onchaind (after 3 blocks) tells us
   to fail the HTLC.
4. hout->failonion is set, but hout->hin has not been failed yet.  We
   do a sanity check and print a nasty message, and fail it with
   WIRE_PERMANENT_CHANNEL_FAILURE instead of relaying the error.

So handle this case explicitly.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-06-26 14:10:01 +09:30
parent 353361a05c
commit 517828adb2
2 changed files with 13 additions and 2 deletions

View File

@ -1573,6 +1573,18 @@ void onchain_failed_our_htlc(const struct channel *channel,
return;
}
/* We can have hout->failonion (which gets set when we process the
* received commitment_signed), but not failed hin yet, because the peer
* hadn't revoke_and_acked our own commitment without that htlc. */
if (hout->failonion && hout->in
&& hout->in->badonion == 0
&& !hout->in->failonion
&& !hout->in->preimage) {
log_debug(channel->log, "HTLC out %"PRIu64" can now fail HTLC upstream!",
htlc->id);
fail_in_htlc(hout->in, hout->failonion);
}
/* Don't fail twice (or if already succeeded)! */
if (hout->failonion || hout->failmsg || hout->preimage) {
log_debug(channel->log, "HTLC id %"PRIu64" failonion = %p, failmsg = %p, preimage = %p",

View File

@ -5267,7 +5267,6 @@ def test_pay_bolt11_metadata(node_factory, bitcoind):
l2.daemon.wait_for_log("Unexpected payment_metadata {}".format(b'this is metadata'.hex()))
@pytest.mark.xfail(strict=True)
@pytest.mark.developer("needs to dev-disconnect")
def test_pay_middle_fail(node_factory, bitcoind, executor):
"""Test the case where a HTLC is failed, but not on peer's side, then
@ -5308,5 +5307,5 @@ def test_pay_middle_fail(node_factory, bitcoind, executor):
bitcoind.generate_block(3, wait_for_mempool=1)
# And that will fail upstream
with pytest.raises(RpcError, match=r'WIRE_PERMANENT_CHANNEL_FAILURE'):
with pytest.raises(RpcError, match=r'WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS'):
l1.rpc.waitsendpay('00' * 32)