From d943d8abbc81ef2807863a0084184fead5e1cd8b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 28 Aug 2019 13:38:26 +0930 Subject: [PATCH] lightningd: expose full onion error when we have it. Mainly useful for testing. In particular, we don't save it to the db. Signed-off-by: Rusty Russell --- lightningd/pay.c | 21 ++++++++++++++++++--- tests/test_pay.py | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/lightningd/pay.c b/lightningd/pay.c index 818caec16..1ea819155 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -25,6 +25,8 @@ struct routing_failure { struct node_id erring_node; struct short_channel_id erring_channel; int channel_dir; + /* If remote sent us a message, this is it. */ + const u8 *msg; }; /* sendpay command */ @@ -126,7 +128,8 @@ json_add_routefail_info(struct json_stream *js, enum onion_type failcode, const struct node_id *erring_node, const struct short_channel_id *erring_channel, - int channel_dir) + int channel_dir, + const u8 *msg) { const char *failcodename = onion_type_name(failcode); @@ -138,6 +141,8 @@ json_add_routefail_info(struct json_stream *js, json_add_node_id(js, "erring_node", erring_node); json_add_short_channel_id(js, "erring_channel", erring_channel); json_add_num(js, "erring_direction", channel_dir); + if (msg) + json_add_hex_talarr(js, "raw_message", msg); } /* onionreply used if pay_errcode == PAY_UNPARSEABLE_ONION */ @@ -168,7 +173,8 @@ sendpay_fail(struct command *cmd, fail->failcode, &fail->erring_node, &fail->erring_channel, - fail->channel_dir); + fail->channel_dir, + fail->msg); json_object_end(data); return command_failed(cmd, data); } @@ -254,6 +260,7 @@ immediate_routing_failure(const tal_t *ctx, routing_failure->erring_node = ld->id; routing_failure->erring_channel = *channel0; routing_failure->channel_dir = node_id_idx(&ld->id, dstid); + routing_failure->msg = NULL; return routing_failure; } @@ -277,6 +284,7 @@ local_routing_failure(const tal_t *ctx, routing_failure->erring_channel = payment->route_channels[0]; routing_failure->channel_dir = node_id_idx(&ld->id, &payment->route_nodes[0]); + routing_failure->msg = NULL; log_debug(hout->key.channel->log, "local_routing_failure: %u (%s)", hout->failcode, onion_type_name(hout->failcode)); @@ -368,6 +376,8 @@ remote_routing_failure(const tal_t *ctx, routing_failure->erring_node = *erring_node; routing_failure->erring_channel = *erring_channel; routing_failure->channel_dir = dir; + routing_failure->msg = tal_dup_arr(routing_failure, u8, failure->msg, + tal_count(failure->msg), 0); return routing_failure; } @@ -466,6 +476,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, hout->key.id, reply->origin_index, failcode, onion_type_name(failcode)); + log_debug(hout->key.channel->log, "failmsg: %s", + tal_hex(tmpctx, reply->msg)); fail = remote_routing_failure(tmpctx, ld, payment, reply, hout->key.channel->log, @@ -559,6 +571,8 @@ static struct command_result *wait_payment(struct lightningd *ld, fail->erring_node = *failnode; fail->erring_channel = *failchannel; fail->channel_dir = faildirection; + /* FIXME: We don't store this! */ + fail->msg = NULL; return sendpay_fail(cmd, faildestperm ? PAY_DESTINATION_PERM_FAIL @@ -673,7 +687,8 @@ send_payment(struct lightningd *ld, json_add_routefail_info(data, 0, WIRE_UNKNOWN_NEXT_PEER, &ld->id, &route[0].channel_id, - node_id_idx(&ld->id, &route[0].nodeid)); + node_id_idx(&ld->id, &route[0].nodeid), + NULL); json_object_end(data); return command_failed(cmd, data); } diff --git a/tests/test_pay.py b/tests/test_pay.py index 0376855bc..533a3bfe7 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -2190,3 +2190,25 @@ def test_channel_drainage(node_factory, bitcoind): route = l2.rpc.getroute(l1.info['id'], amount, riskfactor=1, fuzzpercent=0)['route'] l2.rpc.sendpay(route, payment_hash) l2.rpc.waitsendpay(payment_hash, TIMEOUT) + + +def test_error_returns_blockheight(node_factory, bitcoind): + """Test that incorrect_or_unknown_payment_details returns block height""" + l1, l2 = node_factory.line_graph(2) + + l1.rpc.sendpay([{'msatoshi': 100, + 'id': l2.info['id'], + 'delay': 10, + 'channel': l1.get_channel_scid(l2)}], + '00' * 32) + + with pytest.raises(RpcError, match=r"INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS.*'erring_index': 1") as err: + l1.rpc.waitsendpay('00' * 32, TIMEOUT) + + # BOLT #4: + # 1. type: PERM|15 (`incorrect_or_unknown_payment_details`) + # 2. data: + # * [`u64`:`htlc_msat`] + # * [`u32`:`height`] + assert (err.value.error['data']['raw_message'] + == '400f{:016x}{:08x}'.format(100, bitcoind.rpc.getblockcount()))