From bfcef9002e938ba720eb56bdc365e34e58cfa798 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 23 Jan 2020 16:19:42 +1030 Subject: [PATCH] lightningd: fix handling of WIRE_UPDATE_FAIL_MALFORMED_HTLC. 1. We asserted that there wouldn't be a raw failcode. 2. We didn't pass the failure information via JSON in this case. Signed-off-by: Rusty Russell --- lightningd/pay.c | 35 +++++++++++++++++++++++++++++++++-- tests/test_misc.py | 1 - 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lightningd/pay.c b/lightningd/pay.c index da4340f1d..8c4ae4964 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -179,7 +179,7 @@ void json_sendpay_fail_fields(struct json_stream *js, /* "immediate_routing_failure" is before payment creation. */ if (payment) json_add_payment_fields(js, payment); - if (pay_errcode == PAY_UNPARSEABLE_ONION) + if (pay_errcode == PAY_UNPARSEABLE_ONION && onionreply) json_add_hex_talarr(js, "onionreply", onionreply->contents); else json_add_routefail_info(js, @@ -487,6 +487,30 @@ remote_routing_failure(const tal_t *ctx, return routing_failure; } +/* If our immediate peer says WIRE_UPDATE_FAIL_MALFORMED_HTLC, we only get a + * code, no onion msg. */ +static struct routing_failure * +badonion_routing_failure(const tal_t *ctx, + struct lightningd *ld, + const struct wallet_payment *payment, + enum onion_type failcode) +{ + struct routing_failure *rf; + + rf = tal(ctx, struct routing_failure); + + rf->erring_index = 0; + rf->failcode = failcode; + rf->msg = NULL; + rf->erring_node = tal_dup(rf, struct node_id, + &payment->route_nodes[0]); + rf->erring_channel = tal_dup(rf, struct short_channel_id, + &payment->route_channels[0]); + rf->channel_dir = node_id_idx(&ld->id, &payment->route_nodes[0]); + + return rf; +} + void payment_store(struct lightningd *ld, struct wallet_payment *payment TAKES) { struct sendpay_command *pc; @@ -551,8 +575,15 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, pay_errcode = PAY_UNPARSEABLE_ONION; fail = NULL; failmsg = NULL; + } else if (hout->failcode) { + /* Direct peer told channeld it's a malformed onion using + * update_fail_malformed_htlc. */ + failmsg = "malformed onion"; + fail = badonion_routing_failure(tmpctx, ld, payment, + hout->failcode); + pay_errcode = PAY_UNPARSEABLE_ONION; } else { - /* Must be remote fail. */ + /* Must be normal remote fail with an onion-wrapped error. */ assert(!hout->failcode); failmsg = "reply from remote"; /* Try to parse reply. */ diff --git a/tests/test_misc.py b/tests/test_misc.py index 8323e430a..fcd79e217 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1591,7 +1591,6 @@ def test_bad_onion(node_factory, bitcoind): assert err.value.error['data']['erring_channel'] == route[1]['channel'] -@pytest.mark.xfail(strict=True) @unittest.skipIf(not DEVELOPER, "Needs DEVELOPER=1 to force onion fail") def test_bad_onion_immediate_peer(node_factory, bitcoind): """Test that we handle the malformed msg when we're the origin"""