diff --git a/channeld/channel.c b/channeld/channel.c index 537d93752..f3a27ef40 100644 --- a/channeld/channel.c +++ b/channeld/channel.c @@ -1985,20 +1985,118 @@ static void handle_preimage(struct peer *peer, const u8 *inmsg) abort(); } +static u8 *foreign_channel_update(const tal_t *ctx, + struct peer *peer, + const struct short_channel_id *scid) +{ + /* FIXME! */ + return NULL; +} + +static u8 *make_failmsg(const tal_t *ctx, + struct peer *peer, + const struct htlc *htlc, + enum onion_type failcode, + const struct short_channel_id *scid) +{ + u8 *msg, *channel_update = NULL; + u32 cltv_expiry = abs_locktime_to_blocks(&htlc->expiry); + + switch (failcode) { + case WIRE_INVALID_REALM: + msg = towire_invalid_realm(ctx); + goto done; + case WIRE_TEMPORARY_NODE_FAILURE: + msg = towire_temporary_node_failure(ctx); + goto done; + case WIRE_PERMANENT_NODE_FAILURE: + msg = towire_permanent_node_failure(ctx); + goto done; + case WIRE_REQUIRED_NODE_FEATURE_MISSING: + msg = towire_required_node_feature_missing(ctx); + goto done; + case WIRE_TEMPORARY_CHANNEL_FAILURE: + channel_update = foreign_channel_update(ctx, peer, scid); + msg = towire_temporary_channel_failure(ctx, channel_update); + goto done; + case WIRE_CHANNEL_DISABLED: + msg = towire_channel_disabled(ctx); + goto done; + case WIRE_PERMANENT_CHANNEL_FAILURE: + msg = towire_permanent_channel_failure(ctx); + goto done; + case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING: + msg = towire_required_channel_feature_missing(ctx); + goto done; + case WIRE_UNKNOWN_NEXT_PEER: + msg = towire_unknown_next_peer(ctx); + goto done; + case WIRE_AMOUNT_BELOW_MINIMUM: + channel_update = foreign_channel_update(ctx, peer, scid); + msg = towire_amount_below_minimum(ctx, htlc->msatoshi, + channel_update); + goto done; + case WIRE_FEE_INSUFFICIENT: + channel_update = foreign_channel_update(ctx, peer, scid); + msg = towire_fee_insufficient(ctx, htlc->msatoshi, + channel_update); + goto done; + case WIRE_INCORRECT_CLTV_EXPIRY: + channel_update = foreign_channel_update(ctx, peer, scid); + msg = towire_incorrect_cltv_expiry(ctx, cltv_expiry, + channel_update); + goto done; + case WIRE_EXPIRY_TOO_SOON: + channel_update = foreign_channel_update(ctx, peer, scid); + msg = towire_expiry_too_soon(ctx, channel_update); + goto done; + case WIRE_EXPIRY_TOO_FAR: + msg = towire_expiry_too_far(ctx); + goto done; + case WIRE_UNKNOWN_PAYMENT_HASH: + msg = towire_unknown_payment_hash(ctx); + goto done; + case WIRE_INCORRECT_PAYMENT_AMOUNT: + msg = towire_incorrect_payment_amount(ctx); + goto done; + case WIRE_FINAL_EXPIRY_TOO_SOON: + msg = towire_final_expiry_too_soon(ctx); + goto done; + case WIRE_FINAL_INCORRECT_CLTV_EXPIRY: + msg = towire_final_incorrect_cltv_expiry(ctx, cltv_expiry); + goto done; + case WIRE_FINAL_INCORRECT_HTLC_AMOUNT: + msg = towire_final_incorrect_htlc_amount(ctx, htlc->msatoshi); + goto done; + case WIRE_INVALID_ONION_VERSION: + case WIRE_INVALID_ONION_HMAC: + case WIRE_INVALID_ONION_KEY: + break; + } + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Asked to create failmsg %u (%s)", + failcode, onion_type_name(failcode)); + +done: + tal_free(channel_update); + return msg; +} + static void handle_fail(struct peer *peer, const u8 *inmsg) { u8 *msg; u64 id; u8 *errpkt; u16 failcode; + struct short_channel_id scid; enum channel_remove_err e; struct htlc *h; if (!fromwire_channel_fail_htlc(inmsg, inmsg, NULL, &id, &errpkt, - &failcode)) + &failcode, &scid)) master_badmsg(WIRE_CHANNEL_FAIL_HTLC, inmsg); - if ((failcode & BADONION) && tal_len(errpkt)) + if (failcode && tal_len(errpkt)) status_failed(STATUS_FAIL_MASTER_IO, "Invalid channel_fail_htlc: %s with errpkt?", onion_type_name(failcode)); @@ -2017,8 +2115,13 @@ static void handle_fail(struct peer *peer, const u8 *inmsg) id, &sha256_of_onion, failcode); } else { - u8 *reply = wrap_onionreply(inmsg, h->shared_secret, - errpkt); + u8 *reply; + + if (failcode) + errpkt = make_failmsg(inmsg, peer, h, + failcode, &scid); + reply = wrap_onionreply(inmsg, h->shared_secret, + errpkt); msg = towire_update_fail_htlc(peer, &peer->channel_id, id, reply); } diff --git a/channeld/channel_wire.csv b/channeld/channel_wire.csv index 190a9a7d5..2a328102d 100644 --- a/channeld/channel_wire.csv +++ b/channeld/channel_wire.csv @@ -97,6 +97,8 @@ channel_fail_htlc,,len,u16 channel_fail_htlc,,error_pkt,len*u8 # If it errcode is != 0, it's a local error, otherwise we're passing thru. channel_fail_htlc,,errcode,u16 +# If errcode & UPDATE, this says which outgoing channel failed. +channel_fail_htlc,,which_channel,struct short_channel_id # Ping/pong test. channel_ping,1011 diff --git a/lightningd/htlc_end.h b/lightningd/htlc_end.h index 7d8c497e5..c7f0cfcdf 100644 --- a/lightningd/htlc_end.h +++ b/lightningd/htlc_end.h @@ -35,11 +35,15 @@ struct htlc_in { /* If a local error, this is non-zero. */ enum onion_type failcode; - /* Either a remote error, or local error if !(failure & BADONION). */ + /* For a remote error. */ const u8 *failuremsg; + /* If failcode & UPDATE, this is the channel which failed. */ + struct short_channel_id failoutchannel; + /* If they fulfilled, here's the preimage. */ struct preimage *preimage; + }; struct htlc_out { @@ -61,7 +65,7 @@ struct htlc_out { /* If a local error, this is non-zero. */ enum onion_type failcode; - /* Either a remote error, or local error if !(failure & BADONION). */ + /* For a remote error. */ const u8 *failuremsg; /* If we fulfilled, here's the preimage. */ diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 514a7877b..7087c1da7 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -79,7 +79,8 @@ static bool htlc_out_update_state(struct peer *peer, static void fail_in_htlc(struct htlc_in *hin, enum onion_type failcode, - const u8 *failuremsg) + const u8 *failuremsg, + const struct short_channel_id *out_channelid) { assert(!hin->preimage); @@ -88,6 +89,12 @@ static void fail_in_htlc(struct htlc_in *hin, if (failuremsg) hin->failuremsg = tal_dup_arr(hin, u8, failuremsg, tal_len(failuremsg), 0); + /* We need this set, since we send it to channeld. */ + if (hin->failcode & UPDATE) + hin->failoutchannel = *out_channelid; + else + memset(&hin->failoutchannel, 0, sizeof(hin->failoutchannel)); + /* We update state now to signal it's in progress, for persistence. */ htlc_in_update_state(hin->key.peer, hin, SENT_REMOVE_HTLC); @@ -95,93 +102,22 @@ static void fail_in_htlc(struct htlc_in *hin, if (!hin->key.peer->owner) return; - if (!hin->failuremsg) { - subd_send_msg(hin->key.peer->owner, - take(towire_channel_fail_htlc(hin, - hin->key.id, - NULL, - hin->failcode))); - } else { - subd_send_msg(hin->key.peer->owner, - take(towire_channel_fail_htlc(hin, hin->key.id, - hin->failuremsg, - 0))); - } -} - -static u8 *make_failmsg(const tal_t *ctx, - struct log *log, - u64 msatoshi, - enum onion_type failcode, - const u8 *channel_update) -{ - switch (failcode) { - case WIRE_INVALID_REALM: - return towire_invalid_realm(ctx); - case WIRE_TEMPORARY_NODE_FAILURE: - return towire_temporary_node_failure(ctx); - case WIRE_PERMANENT_NODE_FAILURE: - return towire_permanent_node_failure(ctx); - case WIRE_REQUIRED_NODE_FEATURE_MISSING: - return towire_required_node_feature_missing(ctx); - case WIRE_TEMPORARY_CHANNEL_FAILURE: - return towire_temporary_channel_failure(ctx, channel_update); - case WIRE_CHANNEL_DISABLED: - return towire_channel_disabled(ctx); - case WIRE_PERMANENT_CHANNEL_FAILURE: - return towire_permanent_channel_failure(ctx); - case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING: - return towire_required_channel_feature_missing(ctx); - case WIRE_UNKNOWN_NEXT_PEER: - return towire_unknown_next_peer(ctx); - case WIRE_AMOUNT_BELOW_MINIMUM: - return towire_amount_below_minimum(ctx, msatoshi, channel_update); - case WIRE_FEE_INSUFFICIENT: - return towire_fee_insufficient(ctx, msatoshi, channel_update); - case WIRE_INCORRECT_CLTV_EXPIRY: - /* FIXME: cltv! */ - return towire_incorrect_cltv_expiry(ctx, 0, channel_update); - case WIRE_EXPIRY_TOO_SOON: - return towire_expiry_too_soon(ctx, channel_update); - case WIRE_EXPIRY_TOO_FAR: - return towire_expiry_too_far(ctx); - case WIRE_UNKNOWN_PAYMENT_HASH: - return towire_unknown_payment_hash(ctx); - case WIRE_INCORRECT_PAYMENT_AMOUNT: - return towire_incorrect_payment_amount(ctx); - case WIRE_FINAL_EXPIRY_TOO_SOON: - return towire_final_expiry_too_soon(ctx); - case WIRE_FINAL_INCORRECT_CLTV_EXPIRY: - /* FIXME: cltv! */ - return towire_final_incorrect_cltv_expiry(ctx, 0); - case WIRE_FINAL_INCORRECT_HTLC_AMOUNT: - return towire_final_incorrect_htlc_amount(ctx, msatoshi); - case WIRE_INVALID_ONION_VERSION: - case WIRE_INVALID_ONION_HMAC: - case WIRE_INVALID_ONION_KEY: - /* We don't have anything to add for these; code is enough */ - return NULL; - } - - log_broken(log, "Asked to create unknown failmsg %u:" - " using temp node failure instead", failcode); - return towire_temporary_node_failure(ctx); + subd_send_msg(hin->key.peer->owner, + take(towire_channel_fail_htlc(hin, + hin->key.id, + hin->failuremsg, + hin->failcode, + &hin->failoutchannel))); } /* 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) +static void local_fail_htlc(struct htlc_in *hin, enum onion_type failcode, + const struct short_channel_id *out_channel) { - u8 *msg; - log_info(hin->key.peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)", hin->key.id, failcode, onion_type_name(failcode)); - /* FIXME: Get update! */ - msg = make_failmsg(hin, hin->key.peer->log, - hin->msatoshi, failcode, NULL); - - fail_in_htlc(hin, failcode, msg); - tal_free(msg); + fail_in_htlc(hin, failcode, NULL, out_channel); } /* localfail are for handing to the local payer if it's local. */ @@ -190,7 +126,8 @@ static void fail_out_htlc(struct htlc_out *hout, const char *localfail) htlc_out_check(hout, __func__); assert(hout->failcode || hout->failuremsg); if (hout->in) { - fail_in_htlc(hout->in, hout->failcode, hout->failuremsg); + fail_in_htlc(hout->in, hout->failcode, hout->failuremsg, + hout->key.peer->scid); } else { payment_failed(hout->key.peer->ld, hout, localfail); } @@ -364,7 +301,9 @@ static void handle_localpay(struct htlc_in *hin, return; fail: - local_fail_htlc(hin, failcode); + /* Final hop never sends an UPDATE. */ + assert(!(failcode & UPDATE)); + local_fail_htlc(hin, failcode, NULL); } /* @@ -378,10 +317,7 @@ static void hout_subd_died(struct htlc_out *hout) "Failing HTLC %"PRIu64" due to peer death", hout->key.id); - hout->failuremsg = make_failmsg(hout, hout->key.peer->log, - hout->msatoshi, - WIRE_TEMPORARY_CHANNEL_FAILURE, - NULL); + hout->failcode = WIRE_TEMPORARY_CHANNEL_FAILURE; fail_out_htlc(hout, "Outgoing subdaemon died"); } @@ -410,7 +346,8 @@ static void rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds, (const char *)failurestr); payment_failed(hout->key.peer->ld, hout, localfail); } else - local_fail_htlc(hout->in, failure_code); + local_fail_htlc(hout->in, failure_code, + hout->key.peer->scid); return; } @@ -480,9 +417,10 @@ static void forward_htlc(struct htlc_in *hin, struct lightningd *ld = hin->key.peer->ld; struct peer *next = peer_by_id(ld, next_hop); - if (!next) { - failcode = WIRE_UNKNOWN_NEXT_PEER; - goto fail; + /* Unknown peer, or peer not ready. */ + if (!next || !next->scid) { + local_fail_htlc(hin, WIRE_UNKNOWN_NEXT_PEER, NULL); + return; } /* BOLT #7: @@ -551,7 +489,7 @@ static void forward_htlc(struct htlc_in *hin, return; fail: - local_fail_htlc(hin, failcode); + local_fail_htlc(hin, failcode, next->scid); } /* Temporary information, while we resolve the next hop */ @@ -578,7 +516,7 @@ static void channel_resolve_reply(struct subd *gossip, const u8 *msg, } if (tal_count(nodes) == 0) { - local_fail_htlc(gr->hin, WIRE_UNKNOWN_NEXT_PEER); + local_fail_htlc(gr->hin, WIRE_UNKNOWN_NEXT_PEER, NULL); return; } else if (tal_count(nodes) != 2) { log_broken(gossip->log, @@ -826,12 +764,10 @@ void onchain_failed_our_htlc(const struct peer *peer, struct htlc_out *hout = find_htlc_out_by_ripemd(peer, &htlc->ripemd); /* Don't fail twice! */ - if (hout->failuremsg) + if (hout->failuremsg || hout->failcode) return; - hout->failuremsg = make_failmsg(hout, peer->log, hout->msatoshi, - WIRE_PERMANENT_CHANNEL_FAILURE, - NULL); + hout->failcode = WIRE_PERMANENT_CHANNEL_FAILURE; if (!hout->in) { char *localfail = tal_fmt(peer, "%s: %s", @@ -840,7 +776,8 @@ void onchain_failed_our_htlc(const struct peer *peer, payment_failed(hout->key.peer->ld, hout, localfail); tal_free(localfail); } else - local_fail_htlc(hout->in, WIRE_PERMANENT_CHANNEL_FAILURE); + local_fail_htlc(hout->in, WIRE_PERMANENT_CHANNEL_FAILURE, + hout->key.peer->scid); } static void remove_htlc_in(struct peer *peer, struct htlc_in *hin) @@ -1294,8 +1231,11 @@ void peer_got_revoke(struct peer *peer, const u8 *msg) if (!failcodes[i]) continue; + /* These are all errors before finding next hop. */ + assert(!(failcodes[i] & UPDATE)); + hin = find_htlc_in(&peer->ld->htlcs_in, peer, changed[i].id); - local_fail_htlc(hin, failcodes[i]); + local_fail_htlc(hin, failcodes[i], NULL); } wallet_channel_save(peer->ld->wallet, peer->channel); }