mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-01 17:47:30 +01:00
lightningd: clean up HTLC error handling.
Some paths were still sending unencrypted failure messages; unify them all. We need to keep the fail_msg around for resubmission if the channeld dies; similarly, we need to keep the htlc_end structure itself after failure, in case the failed HTLC is committed: we can move it to a minimal archive once it's flushed from both sides, however. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
7105085801
commit
6e28412f8f
2 changed files with 61 additions and 90 deletions
|
@ -29,6 +29,9 @@ struct htlc_end {
|
|||
u32 cltv_expiry;
|
||||
struct sha256 payment_hash;
|
||||
|
||||
/* If we failed HTLC, here's the message. */
|
||||
const u8 *fail_msg;
|
||||
|
||||
/* If we are forwarding, remember the shared secret for an
|
||||
* eventual reply */
|
||||
struct secret *shared_secret;
|
||||
|
|
|
@ -791,39 +791,24 @@ struct decoding_htlc {
|
|||
struct secret shared_secret;
|
||||
};
|
||||
|
||||
static void fail_htlc(struct peer *peer, struct htlc_end *hend, const u8 *msg)
|
||||
{
|
||||
u8 *reply = wrap_onionreply(hend, hend->shared_secret, msg);
|
||||
subd_send_msg(peer->owner,
|
||||
take(towire_channel_fail_htlc(peer, hend->htlc_id, reply)));
|
||||
if (taken(msg))
|
||||
tal_free(msg);
|
||||
}
|
||||
|
||||
static void fail_local_htlc(struct peer *peer, struct htlc_end *hend, const u8 *msg)
|
||||
/* This obfuscates the message, whether local or forwarded. */
|
||||
static void relay_htlc_failmsg(struct htlc_end *hend)
|
||||
{
|
||||
u8 *reply;
|
||||
enum onion_type failcode = fromwire_peektype(msg);
|
||||
log_broken(peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
|
||||
hend->htlc_id, failcode, onion_type_name(failcode));
|
||||
|
||||
reply = create_onionreply(hend, hend->shared_secret, msg);
|
||||
fail_htlc(peer, hend, reply);
|
||||
if (!hend->peer->owner)
|
||||
return;
|
||||
|
||||
reply = wrap_onionreply(hend, hend->shared_secret, hend->fail_msg);
|
||||
subd_send_msg(hend->peer->owner,
|
||||
take(towire_channel_fail_htlc(hend, hend->htlc_id, reply)));
|
||||
tal_free(reply);
|
||||
}
|
||||
|
||||
static u8 *make_failmsg(const tal_t *ctx, const struct htlc_end *hend,
|
||||
enum onion_type failcode)
|
||||
enum onion_type failcode,
|
||||
const struct sha256 *onion_sha, const u8 *channel_update)
|
||||
{
|
||||
struct sha256 *onion_sha = NULL;
|
||||
u8 *channel_update = NULL;
|
||||
|
||||
if (failcode & BADONION) {
|
||||
/* FIXME: need htlc_end->sha? */
|
||||
}
|
||||
if (failcode & UPDATE) {
|
||||
/* FIXME: Ask gossip daemon for channel_update. */
|
||||
}
|
||||
|
||||
switch (failcode) {
|
||||
case WIRE_INVALID_REALM:
|
||||
return towire_invalid_realm(ctx);
|
||||
|
@ -873,6 +858,26 @@ static u8 *make_failmsg(const tal_t *ctx, const struct htlc_end *hend,
|
|||
abort();
|
||||
}
|
||||
|
||||
static void fail_htlc(struct htlc_end *hend, enum onion_type failcode,
|
||||
const struct sha256 *onion_sha)
|
||||
{
|
||||
u8 *msg;
|
||||
|
||||
log_broken(hend->peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
|
||||
hend->htlc_id, failcode, onion_type_name(failcode));
|
||||
|
||||
if (failcode & UPDATE) {
|
||||
/* FIXME: Ask gossip daemon for channel_update. */
|
||||
}
|
||||
|
||||
msg = make_failmsg(hend, hend, failcode, onion_sha, NULL);
|
||||
hend->fail_msg = create_onionreply(hend, hend->shared_secret, msg);
|
||||
tal_free(msg);
|
||||
|
||||
relay_htlc_failmsg(hend);
|
||||
}
|
||||
|
||||
|
||||
/* BOLT #4:
|
||||
*
|
||||
* * `amt_to_forward` - The amount in milli-satoshi to forward to the next
|
||||
|
@ -950,7 +955,7 @@ static void handle_localpay(struct htlc_end *hend,
|
|||
u64 amt_to_forward,
|
||||
u32 outgoing_cltv_value)
|
||||
{
|
||||
u8 *err;
|
||||
enum onion_type failcode;
|
||||
struct invoice *invoice;
|
||||
|
||||
/* BOLT #4:
|
||||
|
@ -963,7 +968,7 @@ static void handle_localpay(struct htlc_end *hend,
|
|||
* * [`4`:`incoming_htlc_amt`]
|
||||
*/
|
||||
if (!check_amount(hend, amt_to_forward, hend->msatoshis, 0)) {
|
||||
err = towire_final_incorrect_htlc_amount(hend, hend->msatoshis);
|
||||
failcode = WIRE_FINAL_INCORRECT_HTLC_AMOUNT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -977,13 +982,13 @@ static void handle_localpay(struct htlc_end *hend,
|
|||
* * [`4`:`cltv_expiry`]
|
||||
*/
|
||||
if (!check_ctlv(hend, cltv_expiry, outgoing_cltv_value, 0)) {
|
||||
err = towire_final_incorrect_cltv_expiry(hend, cltv_expiry);
|
||||
failcode = WIRE_FINAL_INCORRECT_CLTV_EXPIRY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
invoice = find_unpaid(hend->peer->ld->dstate.invoices, payment_hash);
|
||||
if (!invoice) {
|
||||
err = towire_unknown_payment_hash(hend);
|
||||
failcode = WIRE_UNKNOWN_PAYMENT_HASH;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -998,10 +1003,10 @@ static void handle_localpay(struct htlc_end *hend,
|
|||
* 1. type: PERM|16 (`incorrect_payment_amount`)
|
||||
*/
|
||||
if (hend->msatoshis < invoice->msatoshi) {
|
||||
err = towire_incorrect_payment_amount(hend);
|
||||
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
|
||||
goto fail;
|
||||
} else if (hend->msatoshis > invoice->msatoshi * 2) {
|
||||
err = towire_incorrect_payment_amount(hend);
|
||||
failcode = WIRE_INCORRECT_PAYMENT_AMOUNT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1021,7 @@ static void handle_localpay(struct htlc_end *hend,
|
|||
cltv_expiry,
|
||||
get_block_height(hend->peer->ld->topology),
|
||||
hend->peer->ld->dstate.config.deadline_blocks);
|
||||
err = towire_final_expiry_too_soon(hend);
|
||||
failcode = WIRE_FINAL_EXPIRY_TOO_SOON;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -1029,8 +1034,7 @@ static void handle_localpay(struct htlc_end *hend,
|
|||
return;
|
||||
|
||||
fail:
|
||||
fail_local_htlc(hend->peer, hend, take(err));
|
||||
tal_free(hend);
|
||||
fail_htlc(hend, failcode, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1040,18 +1044,11 @@ fail:
|
|||
*/
|
||||
static void hend_subd_died(struct htlc_end *hend)
|
||||
{
|
||||
/* FIXME: Ask gossip daemon for channel_update. */
|
||||
u8 *channel_update = NULL;
|
||||
u8 *failmsg = towire_temporary_channel_failure(hend->other_end,
|
||||
channel_update);
|
||||
u8 *msg = towire_channel_fail_htlc(hend->other_end,
|
||||
hend->other_end->htlc_id,
|
||||
failmsg);
|
||||
log_debug(hend->other_end->peer->owner->log,
|
||||
"Failing HTLC %"PRIu64" due to peer death",
|
||||
hend->other_end->htlc_id);
|
||||
subd_send_msg(hend->other_end->peer->owner, take(msg));
|
||||
tal_free(failmsg);
|
||||
|
||||
fail_htlc(hend->other_end, WIRE_TEMPORARY_CHANNEL_FAILURE, NULL);
|
||||
}
|
||||
|
||||
static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
|
||||
|
@ -1075,9 +1072,7 @@ static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
|
|||
onion_type_name(failure_code),
|
||||
(int)tal_len(failurestr), (char *)failurestr);
|
||||
|
||||
msg = make_failmsg(msg, hend->other_end, failure_code);
|
||||
subd_send_msg(hend->other_end->peer->owner, take(msg));
|
||||
tal_free(hend);
|
||||
fail_htlc(hend->other_end, failure_code, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1096,19 +1091,20 @@ static void forward_htlc(struct htlc_end *hend,
|
|||
const struct pubkey *next_hop,
|
||||
const u8 next_onion[TOTAL_PACKET_SIZE])
|
||||
{
|
||||
u8 *err, *msg;
|
||||
u8 *msg;
|
||||
enum onion_type failcode;
|
||||
u64 fee;
|
||||
struct lightningd *ld = hend->peer->ld;
|
||||
struct peer *next = peer_by_id(ld, next_hop);
|
||||
|
||||
if (!next) {
|
||||
err = towire_unknown_next_peer(hend);
|
||||
failcode = WIRE_UNKNOWN_NEXT_PEER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!peer_can_add_htlc(next)) {
|
||||
log_info(next->log, "Attempt to forward HTLC but not ready");
|
||||
err = towire_unknown_next_peer(hend);
|
||||
failcode = WIRE_UNKNOWN_NEXT_PEER;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -1121,22 +1117,19 @@ static void forward_htlc(struct htlc_end *hend,
|
|||
*/
|
||||
if (mul_overflows_u64(amt_to_forward,
|
||||
ld->dstate.config.fee_per_satoshi)) {
|
||||
/* FIXME: Add channel update */
|
||||
err = towire_fee_insufficient(hend, hend->msatoshis, NULL);
|
||||
failcode = WIRE_FEE_INSUFFICIENT;
|
||||
goto fail;
|
||||
}
|
||||
fee = ld->dstate.config.fee_base
|
||||
+ amt_to_forward * ld->dstate.config.fee_per_satoshi / 1000000;
|
||||
if (!check_amount(hend, amt_to_forward, hend->msatoshis, fee)) {
|
||||
/* FIXME: Add channel update */
|
||||
err = towire_fee_insufficient(hend, hend->msatoshis, NULL);
|
||||
failcode = WIRE_FEE_INSUFFICIENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!check_ctlv(hend, cltv_expiry, outgoing_cltv_value,
|
||||
ld->dstate.config.deadline_blocks)) {
|
||||
/* FIXME: Add channel update */
|
||||
err = towire_incorrect_cltv_expiry(hend, cltv_expiry, NULL);
|
||||
failcode = WIRE_INCORRECT_CLTV_EXPIRY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -1156,8 +1149,7 @@ static void forward_htlc(struct htlc_end *hend,
|
|||
outgoing_cltv_value,
|
||||
get_block_height(next->ld->topology),
|
||||
next->ld->dstate.config.deadline_blocks);
|
||||
/* FIXME: Add channel update */
|
||||
err = towire_expiry_too_soon(hend, NULL);
|
||||
failcode = WIRE_EXPIRY_TOO_SOON;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -1178,8 +1170,7 @@ static void forward_htlc(struct htlc_end *hend,
|
|||
return;
|
||||
|
||||
fail:
|
||||
fail_local_htlc(hend->peer, hend, take(err));
|
||||
tal_free(hend);
|
||||
fail_htlc(hend, failcode, NULL);
|
||||
}
|
||||
|
||||
/* We received a resolver reply, which gives us the node_ids of the
|
||||
|
@ -1197,9 +1188,7 @@ static bool channel_resolve_reply(struct subd *gossip, const u8 *msg,
|
|||
}
|
||||
|
||||
if (tal_count(nodes) == 0) {
|
||||
fail_htlc(hend->peer, hend,
|
||||
take(towire_unknown_next_peer(hend)));
|
||||
tal_free(hend);
|
||||
fail_htlc(hend, WIRE_UNKNOWN_NEXT_PEER, NULL);
|
||||
return true;
|
||||
} else if (tal_count(nodes) != 2) {
|
||||
log_broken(gossip->log,
|
||||
|
@ -1248,6 +1237,7 @@ static int peer_accepted_htlc(struct peer *peer, const u8 *msg)
|
|||
hend->peer = peer;
|
||||
hend->other_end = NULL;
|
||||
hend->pay_command = NULL;
|
||||
hend->fail_msg = NULL;
|
||||
|
||||
if (forward) {
|
||||
req = towire_gossip_resolve_channel_request(msg, &hend->next_channel);
|
||||
|
@ -1316,8 +1306,8 @@ static int peer_failed_htlc(struct peer *peer, const u8 *msg)
|
|||
}
|
||||
|
||||
if (hend->other_end) {
|
||||
fail_htlc(hend->other_end->peer, hend->other_end,
|
||||
reason);
|
||||
hend->other_end->fail_msg = tal_steal(hend->other_end, reason);
|
||||
relay_htlc_failmsg(hend->other_end);
|
||||
} else {
|
||||
size_t numhops = tal_count(hend->path_secrets);
|
||||
struct secret *shared_secrets = tal_arr(hend, struct secret, numhops);
|
||||
|
@ -1334,34 +1324,13 @@ static int peer_failed_htlc(struct peer *peer, const u8 *msg)
|
|||
log_info(peer->log, "htlc %"PRIu64" failed with code 0x%04x (%s)",
|
||||
id, failcode, onion_type_name(failcode));
|
||||
}
|
||||
/* FIXME: Apply update if it contains it, etc */
|
||||
payment_failed(peer->ld, hend, NULL, failcode);
|
||||
}
|
||||
tal_free(hend);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: Encrypt! */
|
||||
static u8 *malformed_msg(const tal_t *ctx, enum onion_type type,
|
||||
const struct sha256 *sha256_of_onion)
|
||||
{
|
||||
u8 *channel_update;
|
||||
|
||||
/* FIXME: check the reported SHA matches what we sent! */
|
||||
switch (type) {
|
||||
case WIRE_INVALID_ONION_VERSION:
|
||||
return towire_invalid_onion_version(ctx, sha256_of_onion);
|
||||
case WIRE_INVALID_ONION_HMAC:
|
||||
return towire_invalid_onion_hmac(ctx, sha256_of_onion);
|
||||
case WIRE_INVALID_ONION_KEY:
|
||||
return towire_invalid_onion_key(ctx, sha256_of_onion);
|
||||
default:
|
||||
/* FIXME: Ask gossip daemon for channel_update. */
|
||||
channel_update = NULL;
|
||||
return towire_temporary_channel_failure(ctx, channel_update);
|
||||
}
|
||||
}
|
||||
|
||||
static int peer_failed_malformed_htlc(struct peer *peer, const u8 *msg)
|
||||
{
|
||||
u64 id;
|
||||
|
@ -1388,12 +1357,11 @@ static int peer_failed_malformed_htlc(struct peer *peer, const u8 *msg)
|
|||
/* Not really a local failure, but since the failing
|
||||
* peer could not derive its shared secret it cannot
|
||||
* create a valid HMAC, so we do it on his behalf */
|
||||
fail_local_htlc(hend->other_end->peer, hend->other_end,
|
||||
malformed_msg(msg, failcode, &sha256_of_onion));
|
||||
fail_htlc(hend->other_end, failcode, &sha256_of_onion);
|
||||
} else {
|
||||
payment_failed(peer->ld, hend, NULL, failcode);
|
||||
}
|
||||
tal_free(hend);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue