diff --git a/lightningd/htlc_end.c b/lightningd/htlc_end.c index 459525428..e082a1d9a 100644 --- a/lightningd/htlc_end.c +++ b/lightningd/htlc_end.c @@ -80,8 +80,10 @@ struct htlc_in *htlc_in_check(const struct htlc_in *hin, const char *abortstr) return corrupt(hin, abortstr, "invalid state %s", htlc_state_name(hin->hstate)); else if (hin->failuremsg && hin->preimage) - return corrupt(hin, abortstr, "Both failed and succeeded"); - else if (hin->failuremsg && hin->malformed) + return corrupt(hin, abortstr, "Both failuremsg and succeeded"); + else if (hin->failcode != 0 && hin->preimage) + return corrupt(hin, abortstr, "Both failcode and succeeded"); + else if (hin->failuremsg && (hin->failcode & BADONION)) return corrupt(hin, abortstr, "Both failed and malformed"); return cast_const(struct htlc_in *, hin); @@ -107,8 +109,8 @@ struct htlc_in *new_htlc_in(const tal_t *ctx, sizeof(hin->onion_routing_packet)); hin->hstate = RCVD_ADD_COMMIT; + hin->failcode = 0; hin->failuremsg = NULL; - hin->malformed = 0; hin->preimage = NULL; return htlc_in_check(hin, "new_htlc_in"); @@ -155,8 +157,8 @@ struct htlc_out *new_htlc_out(const tal_t *ctx, sizeof(hout->onion_routing_packet)); hout->hstate = SENT_ADD_HTLC; + hout->failcode = 0; hout->failuremsg = NULL; - hout->malformed = 0; hout->preimage = NULL; hout->in = in; diff --git a/lightningd/htlc_end.h b/lightningd/htlc_end.h index d3e758785..7d8c497e5 100644 --- a/lightningd/htlc_end.h +++ b/lightningd/htlc_end.h @@ -32,11 +32,11 @@ struct htlc_in { /* Shared secret for us to send any failure message. */ struct secret shared_secret; - /* If we failed HTLC, here's the message. */ - const u8 *failuremsg; + /* If a local error, this is non-zero. */ + enum onion_type failcode; - /* If it was malformed, here's the error. */ - enum onion_type malformed; + /* Either a remote error, or local error if !(failure & BADONION). */ + const u8 *failuremsg; /* If they fulfilled, here's the preimage. */ struct preimage *preimage; @@ -58,11 +58,11 @@ struct htlc_out { /* Onion information */ u8 onion_routing_packet[TOTAL_PACKET_SIZE]; - /* If we failed HTLC, here's the message. */ - const u8 *failuremsg; + /* If a local error, this is non-zero. */ + enum onion_type failcode; - /* If it was malformed, here's the error. */ - enum onion_type malformed; + /* Either a remote error, or local error if !(failure & BADONION). */ + const u8 *failuremsg; /* If we fulfilled, here's the preimage. */ struct preimage *preimage; diff --git a/lightningd/pay.c b/lightningd/pay.c index 16c7161cc..3d26f5b85 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -79,41 +79,35 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, const char *localfail) { struct pay_command *pc = hout->pay_command; - enum onion_type failcode; struct onionreply *reply; + enum onion_type failcode; wallet_payment_set_status(ld->wallet, &hout->payment_hash, PAYMENT_FAILED); - /* This gives more details than a generic failure message, - * and also the failuremsg here is unencrypted */ + /* This gives more details than a generic failure message */ if (localfail) { - size_t max = tal_len(hout->failuremsg); - const u8 *p = hout->failuremsg; - failcode = fromwire_u16(&p, &max); - json_pay_failed(pc, NULL, failcode, localfail); + json_pay_failed(pc, NULL, hout->failcode, localfail); return; } - if (hout->malformed) - failcode = hout->malformed; - else { - reply = unwrap_onionreply(pc, pc->path_secrets, - tal_count(pc->path_secrets), - hout->failuremsg); - if (!reply) { - log_info(hout->key.peer->log, - "htlc %"PRIu64" failed with bad reply (%s)", - hout->key.id, - tal_hex(pc, hout->failuremsg)); - failcode = WIRE_PERMANENT_NODE_FAILURE; - } else { - failcode = fromwire_peektype(reply->msg); - log_info(hout->key.peer->log, - "htlc %"PRIu64" failed from %ith node with code 0x%04x (%s)", - hout->key.id, - reply->origin_index, - failcode, onion_type_name(failcode)); - } + /* Must be remote fail. */ + assert(!hout->failcode); + reply = unwrap_onionreply(pc, pc->path_secrets, + tal_count(pc->path_secrets), + hout->failuremsg); + if (!reply) { + log_info(hout->key.peer->log, + "htlc %"PRIu64" failed with bad reply (%s)", + hout->key.id, + tal_hex(pc, hout->failuremsg)); + failcode = WIRE_PERMANENT_NODE_FAILURE; + } else { + failcode = fromwire_peektype(reply->msg); + log_info(hout->key.peer->log, + "htlc %"PRIu64" failed from %ith node with code 0x%04x (%s)", + hout->key.id, + reply->origin_index, + failcode, onion_type_name(failcode)); } /* FIXME: save ids we can turn reply->origin_index into sender. */ diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 777d02d39..14161830b 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -78,16 +78,13 @@ static bool htlc_out_update_state(struct peer *peer, } static void fail_in_htlc(struct htlc_in *hin, - enum onion_type malformed, + enum onion_type failcode, const u8 *failuremsg) { assert(!hin->preimage); - if (malformed) - assert(!failuremsg); - else - assert(failuremsg); - hin->malformed = malformed; + assert(failcode || failuremsg); + hin->failcode = failcode; if (failuremsg) hin->failuremsg = tal_dup_arr(hin, u8, failuremsg, tal_len(failuremsg), 0); @@ -98,11 +95,11 @@ static void fail_in_htlc(struct htlc_in *hin, if (!hin->key.peer->owner) return; - if (hin->malformed) { + if (!hin->failuremsg) { subd_send_msg(hin->key.peer->owner, take(towire_channel_fail_htlc(hin, hin->key.id, - hin->malformed, + hin->failcode, NULL))); } else { u8 *reply; @@ -167,7 +164,8 @@ static u8 *make_failmsg(const tal_t *ctx, case WIRE_INVALID_ONION_VERSION: case WIRE_INVALID_ONION_HMAC: case WIRE_INVALID_ONION_KEY: - fatal("Bad failmsg for %s", onion_type_name(failcode)); + /* We don't have anything to add for these; code is enough */ + return NULL; } log_broken(log, "Asked to create unknown failmsg %u:" @@ -178,33 +176,26 @@ static u8 *make_failmsg(const tal_t *ctx, /* This is used for cases where we can immediately fail the HTLC. */ static void local_fail_htlc(struct htlc_in *hin, enum onion_type failcode) { + u8 *msg; + log_info(hin->key.peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)", hin->key.id, failcode, onion_type_name(failcode)); - if (failcode & BADONION) - fail_in_htlc(hin, failcode, NULL); - else { - u8 *msg; + /* FIXME: Get update! */ + msg = make_failmsg(hin, hin->key.peer->log, + hin->msatoshi, failcode, NULL); - if (failcode & UPDATE) { - /* FIXME: Ask gossip daemon for channel_update. */ - } - - msg = make_failmsg(hin, hin->key.peer->log, - hin->msatoshi, failcode, NULL); - fail_in_htlc(hin, 0, take(create_onionreply(hin, &hin->shared_secret, msg))); - tal_free(msg); - } + fail_in_htlc(hin, failcode, msg); + tal_free(msg); } /* localfail are for handing to the local payer if it's local. */ static void fail_out_htlc(struct htlc_out *hout, const char *localfail) { htlc_out_check(hout, __func__); - assert(hout->malformed || hout->failuremsg); - assert(!hout->malformed || !hout->failuremsg); + assert(hout->failcode || hout->failuremsg); if (hout->in) { - fail_in_htlc(hout->in, hout->malformed, hout->failuremsg); + fail_in_htlc(hout->in, hout->failcode, hout->failuremsg); } else { payment_failed(hout->key.peer->ld, hout, localfail); } @@ -796,13 +787,16 @@ static bool peer_failed_our_htlc(struct peer *peer, if (!htlc_out_update_state(peer, hout, RCVD_REMOVE_COMMIT)) return false; - log_debug(peer->log, "Our HTLC %"PRIu64" failed (%u)", failed->id, - failed->malformed); - if (failed->malformed) - hout->malformed = failed->malformed; - else + hout->failcode = failed->malformed; + if (!failed->malformed) hout->failuremsg = tal_dup_arr(hout, u8, failed->failreason, tal_len(failed->failreason), 0); + + else + hout->failuremsg = NULL; + + log_debug(peer->log, "Our HTLC %"PRIu64" failed (%u)", failed->id, + hout->failcode); htlc_out_check(hout, __func__); return true; } @@ -857,13 +851,13 @@ void onchain_failed_our_htlc(const struct peer *peer, static void remove_htlc_in(struct peer *peer, struct htlc_in *hin) { htlc_in_check(hin, __func__); - assert(hin->failuremsg || hin->preimage || hin->malformed); + assert(hin->failuremsg || hin->preimage || hin->failcode); log_debug(peer->log, "Removing in HTLC %"PRIu64" state %s %s", hin->key.id, htlc_state_name(hin->hstate), - hin->failuremsg ? "FAILED" - : hin->malformed ? "MALFORMED" - : "FULFILLED"); + hin->preimage ? "FULFILLED" + : hin->failcode ? onion_type_name(hin->failcode) + : "REMOTEFAIL"); /* If we fulfilled their HTLC, credit us. */ if (hin->preimage) { @@ -879,12 +873,12 @@ static void remove_htlc_in(struct peer *peer, struct htlc_in *hin) static void remove_htlc_out(struct peer *peer, struct htlc_out *hout) { htlc_out_check(hout, __func__); - assert(hout->failuremsg || hout->preimage || hout->malformed); + assert(hout->failuremsg || hout->preimage || hout->failcode); log_debug(peer->log, "Removing out HTLC %"PRIu64" state %s %s", hout->key.id, htlc_state_name(hout->hstate), - hout->failuremsg ? "FAILED" - : hout->malformed ? "MALFORMED" - : "FULFILLED"); + hout->preimage ? "FULFILLED" + : hout->failcode ? onion_type_name(hout->failcode) + : "REMOTEFAIL"); /* If it's failed, now we can forward since it's completely locked-in */ if (!hout->preimage) { diff --git a/wallet/wallet.c b/wallet/wallet.c index 70619cd92..2a5cc68ac 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -901,8 +901,9 @@ static bool wallet_stmt2htlc_in(const struct wallet_channel *channel, memcpy(&in->onion_routing_packet, sqlite3_column_blob(stmt, 8), sizeof(in->onion_routing_packet)); + /* FIXME: These need to be saved in db! */ in->failuremsg = NULL; - in->malformed = 0; + in->failcode = 0; return ok; } @@ -936,7 +937,7 @@ static bool wallet_stmt2htlc_out(const struct wallet_channel *channel, sizeof(out->onion_routing_packet)); out->failuremsg = NULL; - out->malformed = 0; + out->failcode = 0; /* Need to defer wiring until we can look up all incoming * htlcs, will wire using origin_htlc_id */