Browse Source

lightningd: unify pay vs forward path when handling failures.

It's a bit tricky since we want to hand more verbose errors to the local
case, but the locally-created and forwarded paths had diverged (the local
one missing some things).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
parent
commit
7882bc0536
  1. 53
      lightningd/pay.c
  2. 3
      lightningd/pay.h
  3. 98
      lightningd/peer_htlcs.c
  4. 6
      lightningd/peer_htlcs.h

53
lightningd/pay.c

@ -9,6 +9,7 @@
#include <lightningd/channel/gen_channel_wire.h> #include <lightningd/channel/gen_channel_wire.h>
#include <lightningd/lightningd.h> #include <lightningd/lightningd.h>
#include <lightningd/peer_control.h> #include <lightningd/peer_control.h>
#include <lightningd/peer_htlcs.h>
#include <lightningd/sphinx.h> #include <lightningd/sphinx.h>
#include <lightningd/subd.h> #include <lightningd/subd.h>
#include <sodium/randombytes.h> #include <sodium/randombytes.h>
@ -70,12 +71,23 @@ void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
hout->pay_command->out = NULL; hout->pay_command->out = NULL;
} }
void payment_failed(struct lightningd *ld, const struct htlc_out *hout) void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
const char *localfail)
{ {
struct pay_command *pc = hout->pay_command; struct pay_command *pc = hout->pay_command;
enum onion_type failcode; enum onion_type failcode;
struct onionreply *reply; struct onionreply *reply;
/* This gives more details than a generic failure message,
* and also the failuremsg here is unencrypted */
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);
return;
}
if (hout->malformed) if (hout->malformed)
failcode = hout->malformed; failcode = hout->malformed;
else { else {
@ -106,35 +118,6 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout)
json_pay_failed(pc, NULL, failcode, "reply from remote"); json_pay_failed(pc, NULL, failcode, "reply from remote");
} }
static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
struct pay_command *pc)
{
u16 failcode;
u8 *failstr;
if (!fromwire_channel_offer_htlc_reply(msg, msg, NULL,
&pc->out->key.id,
&failcode, &failstr)) {
json_pay_failed(pc, &subd->ld->dstate.id, -1,
"daemon bad response");
return false;
}
if (failcode != 0) {
/* Make sure we have a nul-terminated string. */
char *str = (char *)tal_dup_arr(msg, u8,
failstr, tal_len(failstr), 1);
str[tal_len(failstr)] = 0;
json_pay_failed(pc, &subd->ld->dstate.id, failcode, str);
return true;
}
/* HTLC endpoint now owned by lightningd. */
tal_steal(subd->ld, pc->out);
connect_htlc_out(&subd->ld->htlcs_out, pc->out);
return true;
}
/* When JSON RPC goes away, cmd is freed: detach from any running paycommand */ /* When JSON RPC goes away, cmd is freed: detach from any running paycommand */
static void remove_cmd_from_pc(struct command *cmd, struct pay_command *pc) static void remove_cmd_from_pc(struct command *cmd, struct pay_command *pc)
{ {
@ -179,7 +162,6 @@ static void json_sendpay(struct command *cmd,
struct hop_data first_hop_data; struct hop_data first_hop_data;
u64 amount, lastamount; u64 amount, lastamount;
struct onionpacket *packet; struct onionpacket *packet;
u8 *msg;
struct secret *path_secrets; struct secret *path_secrets;
if (!json_get_params(buffer, params, if (!json_get_params(buffer, params,
@ -357,15 +339,10 @@ static void json_sendpay(struct command *cmd,
pc->msatoshi = lastamount; pc->msatoshi = lastamount;
pc->path_secrets = tal_steal(pc, path_secrets); pc->path_secrets = tal_steal(pc, path_secrets);
pc->out = new_htlc_out(pc, peer, amount, first_hop_data.outgoing_cltv,
&rhash, onion, NULL, pc);
log_info(ld->log, "Sending %"PRIu64" over %zu hops to deliver %"PRIu64, log_info(ld->log, "Sending %"PRIu64" over %zu hops to deliver %"PRIu64,
amount, n_hops, lastamount); amount, n_hops, lastamount);
msg = towire_channel_offer_htlc(pc, amount, pc->out = send_htlc_out(peer, amount, first_hop_data.outgoing_cltv,
first_hop_data.outgoing_cltv, &rhash, onion, NULL, pc);
&pc->rhash, onion);
subd_req(pc, peer->owner, take(msg), -1, 0, rcvd_htlc_reply, pc);
/* Wait until we get response. */ /* Wait until we get response. */
tal_add_destructor2(cmd, remove_cmd_from_pc, pc); tal_add_destructor2(cmd, remove_cmd_from_pc, pc);

3
lightningd/pay.h

@ -11,6 +11,7 @@ struct pubkey;
void payment_succeeded(struct lightningd *ld, struct htlc_out *hout, void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
const struct preimage *rval); const struct preimage *rval);
void payment_failed(struct lightningd *ld, const struct htlc_out *hout); void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
const char *localfail);
#endif /* LIGHTNING_LIGHTNINGD_PAY_H */ #endif /* LIGHTNING_LIGHTNINGD_PAY_H */

98
lightningd/peer_htlcs.c

@ -52,7 +52,7 @@ static void relay_htlc_failmsg(struct htlc_in *hin)
} }
} }
static u8 *make_failmsg(const tal_t *ctx, const struct htlc_in *hin, static u8 *make_failmsg(const tal_t *ctx, u64 msatoshi,
enum onion_type failcode, enum onion_type failcode,
const u8 *channel_update) const u8 *channel_update)
{ {
@ -76,9 +76,9 @@ static u8 *make_failmsg(const tal_t *ctx, const struct htlc_in *hin,
case WIRE_UNKNOWN_NEXT_PEER: case WIRE_UNKNOWN_NEXT_PEER:
return towire_unknown_next_peer(ctx); return towire_unknown_next_peer(ctx);
case WIRE_AMOUNT_BELOW_MINIMUM: case WIRE_AMOUNT_BELOW_MINIMUM:
return towire_amount_below_minimum(ctx, hin->msatoshi, channel_update); return towire_amount_below_minimum(ctx, msatoshi, channel_update);
case WIRE_FEE_INSUFFICIENT: case WIRE_FEE_INSUFFICIENT:
return towire_fee_insufficient(ctx, hin->msatoshi, channel_update); return towire_fee_insufficient(ctx, msatoshi, channel_update);
case WIRE_INCORRECT_CLTV_EXPIRY: case WIRE_INCORRECT_CLTV_EXPIRY:
/* FIXME: ctlv! */ /* FIXME: ctlv! */
return towire_incorrect_cltv_expiry(ctx, 0, channel_update); return towire_incorrect_cltv_expiry(ctx, 0, channel_update);
@ -94,12 +94,11 @@ static u8 *make_failmsg(const tal_t *ctx, const struct htlc_in *hin,
/* FIXME: ctlv! */ /* FIXME: ctlv! */
return towire_final_incorrect_cltv_expiry(ctx, 0); return towire_final_incorrect_cltv_expiry(ctx, 0);
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT: case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
return towire_final_incorrect_htlc_amount(ctx, hin->msatoshi); return towire_final_incorrect_htlc_amount(ctx, msatoshi);
case WIRE_INVALID_ONION_VERSION: case WIRE_INVALID_ONION_VERSION:
case WIRE_INVALID_ONION_HMAC: case WIRE_INVALID_ONION_HMAC:
case WIRE_INVALID_ONION_KEY: case WIRE_INVALID_ONION_KEY:
log_broken(hin->key.peer->log, "Bad failmsg for %s", fatal("Bad failmsg for %s", onion_type_name(failcode));
onion_type_name(failcode));
} }
abort(); abort();
} }
@ -118,7 +117,7 @@ static void fail_htlc(struct htlc_in *hin, enum onion_type failcode)
/* FIXME: Ask gossip daemon for channel_update. */ /* FIXME: Ask gossip daemon for channel_update. */
} }
msg = make_failmsg(hin, hin, failcode, NULL); msg = make_failmsg(hin, hin->msatoshi, failcode, NULL);
hin->failuremsg = create_onionreply(hin, &hin->shared_secret, hin->failuremsg = create_onionreply(hin, &hin->shared_secret,
msg); msg);
tal_free(msg); tal_free(msg);
@ -127,6 +126,27 @@ static void fail_htlc(struct htlc_in *hin, enum onion_type failcode)
relay_htlc_failmsg(hin); relay_htlc_failmsg(hin);
} }
/* 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);
if (hout->in) {
if (hout->in->malformed)
hout->malformed = hout->in->malformed;
else {
hout->in->failuremsg
= tal_dup_arr(hout->in, u8,
hout->failuremsg,
tal_len(hout->failuremsg),
0);
}
relay_htlc_failmsg(hout->in);
} else {
payment_failed(hout->key.peer->ld, hout, localfail);
}
}
/* BOLT #4: /* BOLT #4:
* *
* * `amt_to_forward` - The amount in milli-satoshi to forward to the next * * `amt_to_forward` - The amount in milli-satoshi to forward to the next
@ -290,13 +310,16 @@ fail:
* *
* We could queue this and wait for it to come back, but this is simple. * We could queue this and wait for it to come back, but this is simple.
*/ */
static void hend_subd_died(struct htlc_out *hout) static void hout_subd_died(struct htlc_out *hout)
{ {
log_debug(hout->in->key.peer->owner->log, log_debug(hout->key.peer->log,
"Failing HTLC %"PRIu64" due to peer death", "Failing HTLC %"PRIu64" due to peer death",
hout->in->key.id); hout->key.id);
fail_htlc(hout->in, WIRE_TEMPORARY_CHANNEL_FAILURE); hout->failuremsg = make_failmsg(hout, hout->msatoshi,
WIRE_TEMPORARY_CHANNEL_FAILURE,
NULL);
fail_out_htlc(hout, "Outgoing subdaemon died");
} }
/* This is where channeld gives us the HTLC id, and also reports if it /* This is where channeld gives us the HTLC id, and also reports if it
@ -347,6 +370,26 @@ static bool rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
return true; return true;
} }
struct htlc_out *send_htlc_out(struct peer *out, u64 amount, u32 cltv,
const struct sha256 *payment_hash,
const u8 *onion_routing_packet,
struct htlc_in *in,
struct pay_command *pc)
{
struct htlc_out *hout;
u8 *msg;
/* Make peer's daemon own it, catch if it dies. */
hout = new_htlc_out(out->owner, out, amount, cltv,
payment_hash, onion_routing_packet, in, pc);
tal_add_destructor(hout, hout_subd_died);
msg = towire_channel_offer_htlc(out, amount, cltv, payment_hash,
onion_routing_packet);
subd_req(out->ld, out->owner, take(msg), -1, 0, rcvd_htlc_reply, hout);
return hout;
}
static void forward_htlc(struct htlc_in *hin, static void forward_htlc(struct htlc_in *hin,
u32 cltv_expiry, u32 cltv_expiry,
const struct sha256 *payment_hash, const struct sha256 *payment_hash,
@ -355,12 +398,10 @@ static void forward_htlc(struct htlc_in *hin,
const struct pubkey *next_hop, const struct pubkey *next_hop,
const u8 next_onion[TOTAL_PACKET_SIZE]) const u8 next_onion[TOTAL_PACKET_SIZE])
{ {
u8 *msg;
enum onion_type failcode; enum onion_type failcode;
u64 fee; u64 fee;
struct lightningd *ld = hin->key.peer->ld; struct lightningd *ld = hin->key.peer->ld;
struct peer *next = peer_by_id(ld, next_hop); struct peer *next = peer_by_id(ld, next_hop);
struct htlc_out *out;
if (!next) { if (!next) {
failcode = WIRE_UNKNOWN_NEXT_PEER; failcode = WIRE_UNKNOWN_NEXT_PEER;
@ -426,17 +467,9 @@ static void forward_htlc(struct htlc_in *hin,
goto fail; goto fail;
} }
/* Make sure daemon owns it, in case it fails. */ send_htlc_out(next, amt_to_forward,
out = new_htlc_out(next->owner, next, amt_to_forward, outgoing_cltv_value, &hin->payment_hash,
outgoing_cltv_value, &hin->payment_hash, next_onion, hin, NULL);
next_onion, hin, NULL);
tal_add_destructor(out, hend_subd_died);
msg = towire_channel_offer_htlc(next, amt_to_forward,
outgoing_cltv_value,
payment_hash, next_onion);
subd_req(next->owner, next->owner, take(msg), -1, 0,
rcvd_htlc_reply, out);
return; return;
fail: fail:
@ -723,20 +756,7 @@ static void remove_htlc_out(struct peer *peer, struct htlc_out *hout)
/* If it's failed, now we can forward since it's completely locked-in */ /* If it's failed, now we can forward since it's completely locked-in */
if (!hout->preimage) { if (!hout->preimage) {
if (hout->in) { fail_out_htlc(hout, NULL);
if (hout->in->malformed)
hout->malformed = hout->in->malformed;
else {
hout->in->failuremsg
= tal_dup_arr(hout->in, u8,
hout->failuremsg,
tal_len(hout->failuremsg),
0);
}
relay_htlc_failmsg(hout->in);
} else {
payment_failed(peer->ld, hout);
}
} else { } else {
/* We paid for this HTLC, so deduct balance. */ /* We paid for this HTLC, so deduct balance. */
*peer->balance -= hout->msatoshi; *peer->balance -= hout->msatoshi;
@ -779,7 +799,7 @@ static bool update_out_htlc(struct peer *peer, u64 id, enum htlc_state newstate)
/* First transition into commitment; now it outlives peer. */ /* First transition into commitment; now it outlives peer. */
if (newstate == SENT_ADD_COMMIT) { if (newstate == SENT_ADD_COMMIT) {
tal_del_destructor(hout, hend_subd_died); tal_del_destructor(hout, hout_subd_died);
tal_steal(peer->ld, hout); tal_steal(peer->ld, hout);
/* From now onwards, penalty tx might need this */ /* From now onwards, penalty tx might need this */

6
lightningd/peer_htlcs.h

@ -3,6 +3,7 @@
#define LIGHTNING_LIGHTNINGD_PEER_HTLCS_H #define LIGHTNING_LIGHTNINGD_PEER_HTLCS_H
#include "config.h" #include "config.h"
#include <ccan/short_types/short_types.h> #include <ccan/short_types/short_types.h>
#include <lightningd/derive_basepoints.h>
/* FIXME: Define serialization primitive for this? */ /* FIXME: Define serialization primitive for this? */
struct channel_info { struct channel_info {
@ -30,4 +31,9 @@ int peer_sending_commitsig(struct peer *peer, const u8 *msg);
int peer_got_commitsig(struct peer *peer, const u8 *msg); int peer_got_commitsig(struct peer *peer, const u8 *msg);
int peer_got_revoke(struct peer *peer, const u8 *msg); int peer_got_revoke(struct peer *peer, const u8 *msg);
struct htlc_out *send_htlc_out(struct peer *out, u64 amount, u32 cltv,
const struct sha256 *payment_hash,
const u8 *onion_routing_packet,
struct htlc_in *in,
struct pay_command *pc);
#endif /* LIGHTNING_LIGHTNINGD_PEER_HTLCS_H */ #endif /* LIGHTNING_LIGHTNINGD_PEER_HTLCS_H */

Loading…
Cancel
Save