mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-24 01:24:26 +01:00
gossipd: handle onion errors internally.
As a general rule, lightningd shouldn't parse user packets. We move the parsing into gossipd, and have it respond only to permanent failures. Note that we should *not* unconditionally remove a channel on WIRE_INVALID_ONION_HMAC, as this can be triggered (and we do!) by feeding sendpay a route with an incorrect pubkey. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
4eddf57fd9
commit
afab1f7b3c
@@ -118,13 +118,13 @@ gossip_get_txout_reply,,satoshis,u64
|
|||||||
gossip_get_txout_reply,,len,u16
|
gossip_get_txout_reply,,len,u16
|
||||||
gossip_get_txout_reply,,outscript,len*u8
|
gossip_get_txout_reply,,outscript,len*u8
|
||||||
|
|
||||||
# master->gossipd a routing failure occurred
|
# master->gossipd an htlc failed with this onion error.
|
||||||
gossip_routing_failure,3021
|
gossip_payment_failure,3021
|
||||||
gossip_routing_failure,,erring_node,struct pubkey
|
gossip_payment_failure,,erring_node,struct pubkey
|
||||||
gossip_routing_failure,,erring_channel,struct short_channel_id
|
gossip_payment_failure,,erring_channel,struct short_channel_id
|
||||||
gossip_routing_failure,,failcode,u16
|
gossip_payment_failure,,erring_channel_direction,u8
|
||||||
gossip_routing_failure,,len,u16
|
gossip_payment_failure,,len,u16
|
||||||
gossip_routing_failure,,channel_update,len*u8
|
gossip_payment_failure,,error,len*u8
|
||||||
|
|
||||||
# master -> gossipd: a potential funding outpoint was spent, please forget the eventual channel
|
# master -> gossipd: a potential funding outpoint was spent, please forget the eventual channel
|
||||||
gossip_outpoint_spent,3024
|
gossip_outpoint_spent,3024
|
||||||
|
|||||||
|
@@ -2511,30 +2511,94 @@ static struct io_plan *handle_txout_reply(struct io_conn *conn,
|
|||||||
return daemon_conn_read_next(conn, daemon->master);
|
return daemon_conn_read_next(conn, daemon->master);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fix up the channel_update to include the type if it doesn't currently have
|
||||||
|
* one. See ElementsProject/lightning#1730 and lightningnetwork/lnd#1599 for the
|
||||||
|
* in-depth discussion on why we break message parsing here... */
|
||||||
|
static u8 *patch_channel_update(const tal_t *ctx, u8 *channel_update TAKES)
|
||||||
|
{
|
||||||
|
u8 *fixed;
|
||||||
|
if (channel_update != NULL &&
|
||||||
|
fromwire_peektype(channel_update) != WIRE_CHANNEL_UPDATE) {
|
||||||
|
/* This should be a channel_update, prefix with the
|
||||||
|
* WIRE_CHANNEL_UPDATE type, but isn't. Let's prefix it. */
|
||||||
|
fixed = tal_arr(ctx, u8, 0);
|
||||||
|
towire_u16(&fixed, WIRE_CHANNEL_UPDATE);
|
||||||
|
towire(&fixed, channel_update, tal_bytelen(channel_update));
|
||||||
|
if (taken(channel_update))
|
||||||
|
tal_free(channel_update);
|
||||||
|
return fixed;
|
||||||
|
} else {
|
||||||
|
return tal_dup_arr(ctx, u8,
|
||||||
|
channel_update, tal_count(channel_update), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return NULL if the wrapped onion error message has no channel_update field,
|
||||||
|
* or return the embedded channel_update message otherwise. */
|
||||||
|
static u8 *channel_update_from_onion_error(const tal_t *ctx,
|
||||||
|
const u8 *onion_message)
|
||||||
|
{
|
||||||
|
u8 *channel_update = NULL;
|
||||||
|
u64 unused64;
|
||||||
|
u32 unused32;
|
||||||
|
|
||||||
|
/* Identify failcodes that have some channel_update.
|
||||||
|
*
|
||||||
|
* TODO > BOLT 1.0: Add new failcodes when updating to a
|
||||||
|
* new BOLT version. */
|
||||||
|
if (!fromwire_temporary_channel_failure(ctx,
|
||||||
|
onion_message,
|
||||||
|
&channel_update) &&
|
||||||
|
!fromwire_amount_below_minimum(ctx,
|
||||||
|
onion_message, &unused64,
|
||||||
|
&channel_update) &&
|
||||||
|
!fromwire_fee_insufficient(ctx,
|
||||||
|
onion_message, &unused64,
|
||||||
|
&channel_update) &&
|
||||||
|
!fromwire_incorrect_cltv_expiry(ctx,
|
||||||
|
onion_message, &unused32,
|
||||||
|
&channel_update) &&
|
||||||
|
!fromwire_expiry_too_soon(ctx,
|
||||||
|
onion_message,
|
||||||
|
&channel_update))
|
||||||
|
/* No channel update. */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return patch_channel_update(ctx, take(channel_update));
|
||||||
|
}
|
||||||
|
|
||||||
/*~ lightningd tells us when a payment has failed; we mark the channel (or
|
/*~ lightningd tells us when a payment has failed; we mark the channel (or
|
||||||
* node) unusable here (maybe temporarily), and unpack and channel_update
|
* node) unusable here if it's a permanent failure, and unpack any
|
||||||
* contained in the error. */
|
* channel_update contained in the error. */
|
||||||
static struct io_plan *handle_routing_failure(struct io_conn *conn,
|
static struct io_plan *handle_payment_failure(struct io_conn *conn,
|
||||||
struct daemon *daemon,
|
struct daemon *daemon,
|
||||||
const u8 *msg)
|
const u8 *msg)
|
||||||
{
|
{
|
||||||
struct pubkey erring_node;
|
struct pubkey erring_node;
|
||||||
struct short_channel_id erring_channel;
|
struct short_channel_id erring_channel;
|
||||||
u16 failcode;
|
u8 erring_channel_direction;
|
||||||
|
u8 *error;
|
||||||
|
enum onion_type failcode;
|
||||||
u8 *channel_update;
|
u8 *channel_update;
|
||||||
|
|
||||||
if (!fromwire_gossip_routing_failure(msg,
|
if (!fromwire_gossip_payment_failure(msg, msg,
|
||||||
msg,
|
|
||||||
&erring_node,
|
&erring_node,
|
||||||
&erring_channel,
|
&erring_channel,
|
||||||
&failcode,
|
&erring_channel_direction,
|
||||||
&channel_update))
|
&error))
|
||||||
master_badmsg(WIRE_GOSSIP_ROUTING_FAILURE, msg);
|
master_badmsg(WIRE_GOSSIP_PAYMENT_FAILURE, msg);
|
||||||
|
|
||||||
|
failcode = fromwire_peektype(error);
|
||||||
|
channel_update = channel_update_from_onion_error(tmpctx, error);
|
||||||
|
if (channel_update)
|
||||||
|
status_debug("Extracted channel_update %s from onionreply %s",
|
||||||
|
tal_hex(tmpctx, channel_update),
|
||||||
|
tal_hex(tmpctx, error));
|
||||||
routing_failure(daemon->rstate,
|
routing_failure(daemon->rstate,
|
||||||
&erring_node,
|
&erring_node,
|
||||||
&erring_channel,
|
&erring_channel,
|
||||||
(enum onion_type) failcode,
|
erring_channel_direction,
|
||||||
|
failcode,
|
||||||
channel_update);
|
channel_update);
|
||||||
|
|
||||||
return daemon_conn_read_next(conn, daemon->master);
|
return daemon_conn_read_next(conn, daemon->master);
|
||||||
@@ -2550,7 +2614,7 @@ static struct io_plan *handle_outpoint_spent(struct io_conn *conn,
|
|||||||
struct chan *chan;
|
struct chan *chan;
|
||||||
struct routing_state *rstate = daemon->rstate;
|
struct routing_state *rstate = daemon->rstate;
|
||||||
if (!fromwire_gossip_outpoint_spent(msg, &scid))
|
if (!fromwire_gossip_outpoint_spent(msg, &scid))
|
||||||
master_badmsg(WIRE_GOSSIP_ROUTING_FAILURE, msg);
|
master_badmsg(WIRE_GOSSIP_OUTPOINT_SPENT, msg);
|
||||||
|
|
||||||
chan = get_channel(rstate, &scid);
|
chan = get_channel(rstate, &scid);
|
||||||
if (chan) {
|
if (chan) {
|
||||||
@@ -2587,7 +2651,7 @@ static struct io_plan *handle_local_channel_close(struct io_conn *conn,
|
|||||||
struct chan *chan;
|
struct chan *chan;
|
||||||
struct routing_state *rstate = daemon->rstate;
|
struct routing_state *rstate = daemon->rstate;
|
||||||
if (!fromwire_gossip_local_channel_close(msg, &scid))
|
if (!fromwire_gossip_local_channel_close(msg, &scid))
|
||||||
master_badmsg(WIRE_GOSSIP_ROUTING_FAILURE, msg);
|
master_badmsg(WIRE_GOSSIP_LOCAL_CHANNEL_CLOSE, msg);
|
||||||
|
|
||||||
chan = get_channel(rstate, &scid);
|
chan = get_channel(rstate, &scid);
|
||||||
if (chan)
|
if (chan)
|
||||||
@@ -2621,8 +2685,8 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
|||||||
case WIRE_GOSSIP_GET_TXOUT_REPLY:
|
case WIRE_GOSSIP_GET_TXOUT_REPLY:
|
||||||
return handle_txout_reply(conn, daemon, msg);
|
return handle_txout_reply(conn, daemon, msg);
|
||||||
|
|
||||||
case WIRE_GOSSIP_ROUTING_FAILURE:
|
case WIRE_GOSSIP_PAYMENT_FAILURE:
|
||||||
return handle_routing_failure(conn, daemon, msg);
|
return handle_payment_failure(conn, daemon, msg);
|
||||||
|
|
||||||
case WIRE_GOSSIP_OUTPOINT_SPENT:
|
case WIRE_GOSSIP_OUTPOINT_SPENT:
|
||||||
return handle_outpoint_spent(conn, daemon, msg);
|
return handle_outpoint_spent(conn, daemon, msg);
|
||||||
|
|||||||
@@ -1563,65 +1563,57 @@ struct route_hop *get_route(const tal_t *ctx, struct routing_state *rstate,
|
|||||||
return hops;
|
return hops;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* routing_failure_channel_out - Handle routing failure on a specific channel
|
|
||||||
*
|
|
||||||
* If we want to delete the channel, we reparent it to disposal_context.
|
|
||||||
*/
|
|
||||||
static void routing_failure_channel_out(const tal_t *disposal_context,
|
|
||||||
struct node *node,
|
|
||||||
enum onion_type failcode,
|
|
||||||
struct chan *chan,
|
|
||||||
time_t now)
|
|
||||||
{
|
|
||||||
/* BOLT #4:
|
|
||||||
*
|
|
||||||
* - if the PERM bit is NOT set:
|
|
||||||
* - SHOULD restore the channels as it receives new `channel_update`s.
|
|
||||||
*/
|
|
||||||
if (failcode & PERM)
|
|
||||||
/* Set it up to be pruned. */
|
|
||||||
tal_steal(disposal_context, chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
void routing_failure(struct routing_state *rstate,
|
void routing_failure(struct routing_state *rstate,
|
||||||
const struct pubkey *erring_node_pubkey,
|
const struct pubkey *erring_node_pubkey,
|
||||||
const struct short_channel_id *scid,
|
const struct short_channel_id *scid,
|
||||||
|
int erring_direction,
|
||||||
enum onion_type failcode,
|
enum onion_type failcode,
|
||||||
const u8 *channel_update)
|
const u8 *channel_update)
|
||||||
{
|
{
|
||||||
struct node *node;
|
|
||||||
time_t now = time_now().ts.tv_sec;
|
|
||||||
|
|
||||||
status_trace("Received routing failure 0x%04x (%s), "
|
status_trace("Received routing failure 0x%04x (%s), "
|
||||||
"erring node %s, "
|
"erring node %s, "
|
||||||
"channel %s",
|
"channel %s/%u",
|
||||||
(int) failcode, onion_type_name(failcode),
|
(int) failcode, onion_type_name(failcode),
|
||||||
type_to_string(tmpctx, struct pubkey, erring_node_pubkey),
|
type_to_string(tmpctx, struct pubkey, erring_node_pubkey),
|
||||||
type_to_string(tmpctx, struct short_channel_id, scid));
|
type_to_string(tmpctx, struct short_channel_id, scid),
|
||||||
|
erring_direction);
|
||||||
|
|
||||||
node = get_node(rstate, erring_node_pubkey);
|
/* lightningd will only extract this if UPDATE is set. */
|
||||||
if (!node) {
|
if (channel_update) {
|
||||||
status_unusual("routing_failure: Erring node %s not in map",
|
u8 *err = handle_channel_update(rstate, channel_update, "error");
|
||||||
type_to_string(tmpctx, struct pubkey,
|
if (err) {
|
||||||
erring_node_pubkey));
|
status_unusual("routing_failure: "
|
||||||
/* No node, so no channel, so any channel_update
|
"bad channel_update %s",
|
||||||
* can also be ignored. */
|
sanitize_error(err, err, NULL));
|
||||||
return;
|
tal_free(err);
|
||||||
|
}
|
||||||
|
} else if (failcode & UPDATE) {
|
||||||
|
status_unusual("routing_failure: "
|
||||||
|
"UPDATE bit set, no channel_update. "
|
||||||
|
"failcode: 0x%04x",
|
||||||
|
(int) failcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BOLT #4:
|
/* We respond to permanent errors, ignore the rest: they're
|
||||||
*
|
* for the pay command to worry about. */
|
||||||
* - if the NODE bit is set:
|
if (!(failcode & PERM))
|
||||||
* - SHOULD remove all channels connected with the erring node from
|
return;
|
||||||
* consideration.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (failcode & NODE) {
|
if (failcode & NODE) {
|
||||||
for (int i = 0; i < tal_count(node->chans); ++i) {
|
struct node *node = get_node(rstate, erring_node_pubkey);
|
||||||
routing_failure_channel_out(tmpctx, node, failcode,
|
if (!node) {
|
||||||
node->chans[i],
|
status_unusual("routing_failure: Erring node %s not in map",
|
||||||
now);
|
type_to_string(tmpctx, struct pubkey,
|
||||||
|
erring_node_pubkey));
|
||||||
|
} else {
|
||||||
|
status_trace("Deleting node %s",
|
||||||
|
type_to_string(tmpctx,
|
||||||
|
struct pubkey,
|
||||||
|
&node->id));
|
||||||
|
for (size_t i = 0; i < tal_count(node->chans); ++i) {
|
||||||
|
/* Set it up to be pruned. */
|
||||||
|
tal_steal(tmpctx, node->chans[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct chan *chan = get_channel(rstate, scid);
|
struct chan *chan = get_channel(rstate, scid);
|
||||||
@@ -1632,49 +1624,21 @@ void routing_failure(struct routing_state *rstate,
|
|||||||
type_to_string(tmpctx,
|
type_to_string(tmpctx,
|
||||||
struct short_channel_id,
|
struct short_channel_id,
|
||||||
scid));
|
scid));
|
||||||
else if (chan->nodes[0] != node && chan->nodes[1] != node)
|
else {
|
||||||
status_unusual("routing_failure: "
|
/* This error can be triggered by sendpay if caller
|
||||||
"Channel %s does not connect to %s",
|
* uses the wrong key for dest. */
|
||||||
type_to_string(tmpctx,
|
if (failcode == WIRE_INVALID_ONION_HMAC
|
||||||
struct short_channel_id,
|
&& !pubkey_eq(&chan->nodes[!erring_direction]->id,
|
||||||
scid),
|
erring_node_pubkey))
|
||||||
type_to_string(tmpctx, struct pubkey,
|
|
||||||
erring_node_pubkey));
|
|
||||||
else
|
|
||||||
routing_failure_channel_out(tmpctx,
|
|
||||||
node, failcode, chan, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the channel if UPDATE failcode. Do
|
|
||||||
* this after deactivating, so that if the
|
|
||||||
* channel_update is newer it will be
|
|
||||||
* reactivated. */
|
|
||||||
if (failcode & UPDATE) {
|
|
||||||
u8 *err;
|
|
||||||
if (tal_count(channel_update) == 0) {
|
|
||||||
/* Suppress UNUSUAL log if local failure */
|
|
||||||
if (pubkey_eq(erring_node_pubkey, &rstate->local_id))
|
|
||||||
return;
|
return;
|
||||||
status_unusual("routing_failure: "
|
|
||||||
"UPDATE bit set, no channel_update. "
|
status_trace("Deleting channel %s",
|
||||||
"failcode: 0x%04x",
|
type_to_string(tmpctx,
|
||||||
(int) failcode);
|
struct short_channel_id,
|
||||||
return;
|
scid));
|
||||||
|
/* Set it up to be deleted. */
|
||||||
|
tal_steal(tmpctx, chan);
|
||||||
}
|
}
|
||||||
err = handle_channel_update(rstate, channel_update, "error");
|
|
||||||
if (err) {
|
|
||||||
status_unusual("routing_failure: "
|
|
||||||
"bad channel_update %s",
|
|
||||||
sanitize_error(err, err, NULL));
|
|
||||||
tal_free(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tal_count(channel_update) != 0)
|
|
||||||
status_unusual("routing_failure: "
|
|
||||||
"UPDATE bit clear, channel_update given. "
|
|
||||||
"failcode: 0x%04x",
|
|
||||||
(int) failcode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ struct route_hop *get_route(const tal_t *ctx, struct routing_state *rstate,
|
|||||||
void routing_failure(struct routing_state *rstate,
|
void routing_failure(struct routing_state *rstate,
|
||||||
const struct pubkey *erring_node,
|
const struct pubkey *erring_node,
|
||||||
const struct short_channel_id *erring_channel,
|
const struct short_channel_id *erring_channel,
|
||||||
|
int erring_direction,
|
||||||
enum onion_type failcode,
|
enum onion_type failcode,
|
||||||
const u8 *channel_update);
|
const u8 *channel_update);
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
|
|||||||
case WIRE_GOSSIP_GET_CHANNEL_PEER:
|
case WIRE_GOSSIP_GET_CHANNEL_PEER:
|
||||||
case WIRE_GOSSIP_GET_TXOUT_REPLY:
|
case WIRE_GOSSIP_GET_TXOUT_REPLY:
|
||||||
case WIRE_GOSSIP_OUTPOINT_SPENT:
|
case WIRE_GOSSIP_OUTPOINT_SPENT:
|
||||||
case WIRE_GOSSIP_ROUTING_FAILURE:
|
case WIRE_GOSSIP_PAYMENT_FAILURE:
|
||||||
case WIRE_GOSSIP_QUERY_SCIDS:
|
case WIRE_GOSSIP_QUERY_SCIDS:
|
||||||
case WIRE_GOSSIP_QUERY_CHANNEL_RANGE:
|
case WIRE_GOSSIP_QUERY_CHANNEL_RANGE:
|
||||||
case WIRE_GOSSIP_SEND_TIMESTAMP_FILTER:
|
case WIRE_GOSSIP_SEND_TIMESTAMP_FILTER:
|
||||||
|
|||||||
149
lightningd/pay.c
149
lightningd/pay.c
@@ -188,63 +188,6 @@ void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
|
|||||||
payment_trigger_success(ld, &hout->payment_hash);
|
payment_trigger_success(ld, &hout->payment_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix up the channel_update to include the type if it doesn't currently have
|
|
||||||
* one. See ElementsProject/lightning#1730 and lightningnetwork/lnd#1599 for the
|
|
||||||
* in-depth discussion on why we break message parsing here... */
|
|
||||||
static u8 *patch_channel_update(const tal_t *ctx, u8 *channel_update TAKES)
|
|
||||||
{
|
|
||||||
u8 *fixed;
|
|
||||||
if (channel_update != NULL &&
|
|
||||||
fromwire_peektype(channel_update) != WIRE_CHANNEL_UPDATE) {
|
|
||||||
/* This should be a channel_update, prefix with the
|
|
||||||
* WIRE_CHANNEL_UPDATE type, but isn't. Let's prefix it. */
|
|
||||||
fixed = tal_arr(ctx, u8, 0);
|
|
||||||
towire_u16(&fixed, WIRE_CHANNEL_UPDATE);
|
|
||||||
towire(&fixed, channel_update, tal_bytelen(channel_update));
|
|
||||||
if (taken(channel_update))
|
|
||||||
tal_free(channel_update);
|
|
||||||
return fixed;
|
|
||||||
} else {
|
|
||||||
return tal_dup_arr(ctx, u8,
|
|
||||||
channel_update, tal_count(channel_update), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return NULL if the wrapped onion error message has no
|
|
||||||
* channel_update field, or return the embedded
|
|
||||||
* channel_update message otherwise. */
|
|
||||||
static u8 *channel_update_from_onion_error(const tal_t *ctx,
|
|
||||||
const u8 *onion_message)
|
|
||||||
{
|
|
||||||
u8 *channel_update = NULL;
|
|
||||||
u64 unused64;
|
|
||||||
u32 unused32;
|
|
||||||
|
|
||||||
/* Identify failcodes that have some channel_update.
|
|
||||||
*
|
|
||||||
* TODO > BOLT 1.0: Add new failcodes when updating to a
|
|
||||||
* new BOLT version. */
|
|
||||||
if (!fromwire_temporary_channel_failure(ctx,
|
|
||||||
onion_message,
|
|
||||||
&channel_update) &&
|
|
||||||
!fromwire_amount_below_minimum(ctx,
|
|
||||||
onion_message, &unused64,
|
|
||||||
&channel_update) &&
|
|
||||||
!fromwire_fee_insufficient(ctx,
|
|
||||||
onion_message, &unused64,
|
|
||||||
&channel_update) &&
|
|
||||||
!fromwire_incorrect_cltv_expiry(ctx,
|
|
||||||
onion_message, &unused32,
|
|
||||||
&channel_update) &&
|
|
||||||
!fromwire_expiry_too_soon(ctx,
|
|
||||||
onion_message,
|
|
||||||
&channel_update))
|
|
||||||
/* No channel update. */
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return patch_channel_update(ctx, take(channel_update));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a struct routing_failure for an immediate failure
|
/* Return a struct routing_failure for an immediate failure
|
||||||
* (returned directly from send_htlc_out). The returned
|
* (returned directly from send_htlc_out). The returned
|
||||||
* failure is allocated from the given context. */
|
* failure is allocated from the given context. */
|
||||||
@@ -269,7 +212,6 @@ immediate_routing_failure(const tal_t *ctx,
|
|||||||
/* FIXME: Don't set at all unless we know. */
|
/* FIXME: Don't set at all unless we know. */
|
||||||
else
|
else
|
||||||
routing_failure->channel_dir = 0;
|
routing_failure->channel_dir = 0;
|
||||||
routing_failure->channel_update = NULL;
|
|
||||||
|
|
||||||
return routing_failure;
|
return routing_failure;
|
||||||
}
|
}
|
||||||
@@ -293,8 +235,9 @@ local_routing_failure(const tal_t *ctx,
|
|||||||
routing_failure->erring_channel = payment->route_channels[0];
|
routing_failure->erring_channel = payment->route_channels[0];
|
||||||
routing_failure->channel_dir = pubkey_idx(&ld->id,
|
routing_failure->channel_dir = pubkey_idx(&ld->id,
|
||||||
&payment->route_nodes[0]);
|
&payment->route_nodes[0]);
|
||||||
routing_failure->channel_update = NULL;
|
|
||||||
|
|
||||||
|
log_debug(hout->key.channel->log, "local_routing_failure: %u (%s)",
|
||||||
|
hout->failcode, onion_type_name(hout->failcode));
|
||||||
return routing_failure;
|
return routing_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,14 +247,13 @@ local_routing_failure(const tal_t *ctx,
|
|||||||
* failure to report (allocated from ctx) otherwise. */
|
* failure to report (allocated from ctx) otherwise. */
|
||||||
static struct routing_failure*
|
static struct routing_failure*
|
||||||
remote_routing_failure(const tal_t *ctx,
|
remote_routing_failure(const tal_t *ctx,
|
||||||
|
struct lightningd *ld,
|
||||||
bool *p_retry_plausible,
|
bool *p_retry_plausible,
|
||||||
bool *p_report_to_gossipd,
|
|
||||||
const struct wallet_payment *payment,
|
const struct wallet_payment *payment,
|
||||||
const struct onionreply *failure,
|
const struct onionreply *failure,
|
||||||
struct log *log)
|
struct log *log)
|
||||||
{
|
{
|
||||||
enum onion_type failcode = fromwire_peektype(failure->msg);
|
enum onion_type failcode = fromwire_peektype(failure->msg);
|
||||||
u8 *channel_update;
|
|
||||||
struct routing_failure *routing_failure;
|
struct routing_failure *routing_failure;
|
||||||
const struct pubkey *route_nodes;
|
const struct pubkey *route_nodes;
|
||||||
const struct pubkey *erring_node;
|
const struct pubkey *erring_node;
|
||||||
@@ -320,23 +262,13 @@ remote_routing_failure(const tal_t *ctx,
|
|||||||
static const struct short_channel_id dummy_channel = { 0 };
|
static const struct short_channel_id dummy_channel = { 0 };
|
||||||
int origin_index;
|
int origin_index;
|
||||||
bool retry_plausible;
|
bool retry_plausible;
|
||||||
bool report_to_gossipd;
|
|
||||||
int dir;
|
int dir;
|
||||||
|
|
||||||
routing_failure = tal(ctx, struct routing_failure);
|
routing_failure = tal(ctx, struct routing_failure);
|
||||||
route_nodes = payment->route_nodes;
|
route_nodes = payment->route_nodes;
|
||||||
route_channels = payment->route_channels;
|
route_channels = payment->route_channels;
|
||||||
origin_index = failure->origin_index;
|
origin_index = failure->origin_index;
|
||||||
channel_update
|
|
||||||
= channel_update_from_onion_error(routing_failure,
|
|
||||||
failure->msg);
|
|
||||||
if (channel_update)
|
|
||||||
log_debug(log, "Extracted channel_update %s from onionreply %s",
|
|
||||||
tal_hex(tmpctx, channel_update),
|
|
||||||
tal_hex(tmpctx, failure->msg));
|
|
||||||
|
|
||||||
retry_plausible = true;
|
retry_plausible = true;
|
||||||
report_to_gossipd = true;
|
|
||||||
|
|
||||||
assert(origin_index < tal_count(route_nodes));
|
assert(origin_index < tal_count(route_nodes));
|
||||||
|
|
||||||
@@ -356,15 +288,10 @@ remote_routing_failure(const tal_t *ctx,
|
|||||||
retry_plausible = false;
|
retry_plausible = false;
|
||||||
else
|
else
|
||||||
retry_plausible = true;
|
retry_plausible = true;
|
||||||
/* Only send message to gossipd if NODE error;
|
|
||||||
* there is no "next" channel to report as
|
|
||||||
* failing if this is the last node. */
|
|
||||||
if (failcode & NODE)
|
|
||||||
report_to_gossipd = true;
|
|
||||||
else
|
|
||||||
report_to_gossipd = false;
|
|
||||||
erring_node = &route_nodes[origin_index];
|
erring_node = &route_nodes[origin_index];
|
||||||
} else {
|
} else {
|
||||||
|
u8 *gossip_msg;
|
||||||
|
|
||||||
/* Report the *next* channel as failing. */
|
/* Report the *next* channel as failing. */
|
||||||
erring_channel = &route_channels[origin_index + 1];
|
erring_channel = &route_channels[origin_index + 1];
|
||||||
|
|
||||||
@@ -379,46 +306,29 @@ remote_routing_failure(const tal_t *ctx,
|
|||||||
erring_node = &route_nodes[origin_index + 1];
|
erring_node = &route_nodes[origin_index + 1];
|
||||||
} else
|
} else
|
||||||
erring_node = &route_nodes[origin_index];
|
erring_node = &route_nodes[origin_index];
|
||||||
|
|
||||||
|
/* Tell gossipd: it may want to remove channels or even nodes
|
||||||
|
* in response to this, and there may be a channel_update
|
||||||
|
* embedded too */
|
||||||
|
gossip_msg = towire_gossip_payment_failure(NULL,
|
||||||
|
erring_node,
|
||||||
|
erring_channel,
|
||||||
|
dir,
|
||||||
|
failure->msg);
|
||||||
|
subd_send_msg(ld->gossip, take(gossip_msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
routing_failure->erring_index = (unsigned int) (origin_index + 1);
|
routing_failure->erring_index = (unsigned int) (origin_index + 1);
|
||||||
routing_failure->failcode = failcode;
|
routing_failure->failcode = failcode;
|
||||||
routing_failure->erring_node = *erring_node;
|
routing_failure->erring_node = *erring_node;
|
||||||
routing_failure->erring_channel = *erring_channel;
|
routing_failure->erring_channel = *erring_channel;
|
||||||
routing_failure->channel_update = channel_update;
|
|
||||||
routing_failure->channel_dir = dir;
|
routing_failure->channel_dir = dir;
|
||||||
|
|
||||||
*p_retry_plausible = retry_plausible;
|
*p_retry_plausible = retry_plausible;
|
||||||
*p_report_to_gossipd = report_to_gossipd;
|
|
||||||
|
|
||||||
return routing_failure;
|
return routing_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_routing_failure(struct log *log,
|
|
||||||
struct subd *gossip,
|
|
||||||
struct routing_failure *fail)
|
|
||||||
{
|
|
||||||
u8 *gossip_msg;
|
|
||||||
assert(fail);
|
|
||||||
|
|
||||||
log_debug(log,
|
|
||||||
"Reporting route failure to gossipd: 0x%04x (%s) "
|
|
||||||
"node %s channel %s update %s",
|
|
||||||
fail->failcode, onion_type_name(fail->failcode),
|
|
||||||
type_to_string(tmpctx, struct pubkey,
|
|
||||||
&fail->erring_node),
|
|
||||||
type_to_string(tmpctx, struct short_channel_id,
|
|
||||||
&fail->erring_channel),
|
|
||||||
tal_hex(tmpctx, fail->channel_update));
|
|
||||||
|
|
||||||
gossip_msg = towire_gossip_routing_failure(tmpctx,
|
|
||||||
&fail->erring_node,
|
|
||||||
&fail->erring_channel,
|
|
||||||
(u16) fail->failcode,
|
|
||||||
fail->channel_update);
|
|
||||||
subd_send_msg(gossip, gossip_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void payment_store(struct lightningd *ld,
|
void payment_store(struct lightningd *ld,
|
||||||
const struct sha256 *payment_hash)
|
const struct sha256 *payment_hash)
|
||||||
{
|
{
|
||||||
@@ -453,7 +363,6 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
struct routing_failure* fail = NULL;
|
struct routing_failure* fail = NULL;
|
||||||
const char *failmsg;
|
const char *failmsg;
|
||||||
bool retry_plausible;
|
bool retry_plausible;
|
||||||
bool report_to_gossipd;
|
|
||||||
|
|
||||||
payment = wallet_payment_by_hash(tmpctx, ld->wallet,
|
payment = wallet_payment_by_hash(tmpctx, ld->wallet,
|
||||||
&hout->payment_hash);
|
&hout->payment_hash);
|
||||||
@@ -493,14 +402,15 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
fail = local_routing_failure(tmpctx, ld, hout, payment);
|
fail = local_routing_failure(tmpctx, ld, hout, payment);
|
||||||
failmsg = localfail;
|
failmsg = localfail;
|
||||||
retry_plausible = true;
|
retry_plausible = true;
|
||||||
report_to_gossipd = true;
|
|
||||||
} else {
|
} else {
|
||||||
/* Must be remote fail. */
|
/* Must be remote fail. */
|
||||||
assert(!hout->failcode);
|
assert(!hout->failcode);
|
||||||
failmsg = "reply from remote";
|
failmsg = "reply from remote";
|
||||||
/* Try to parse reply. */
|
/* Try to parse reply. */
|
||||||
struct secret *path_secrets = payment->path_secrets;
|
struct secret *path_secrets = payment->path_secrets;
|
||||||
struct onionreply *reply = unwrap_onionreply(tmpctx, path_secrets,
|
struct onionreply *reply;
|
||||||
|
|
||||||
|
reply = unwrap_onionreply(tmpctx, path_secrets,
|
||||||
tal_count(path_secrets),
|
tal_count(path_secrets),
|
||||||
hout->failuremsg);
|
hout->failuremsg);
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
@@ -508,14 +418,9 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
"htlc %"PRIu64" failed with bad reply (%s)",
|
"htlc %"PRIu64" failed with bad reply (%s)",
|
||||||
hout->key.id,
|
hout->key.id,
|
||||||
tal_hex(tmpctx, hout->failuremsg));
|
tal_hex(tmpctx, hout->failuremsg));
|
||||||
/* Cannot report failure. */
|
/* Cannot record failure. */
|
||||||
fail = NULL;
|
fail = NULL;
|
||||||
/* Can now retry; we selected a channel to mark
|
|
||||||
* unroutable by random */
|
|
||||||
retry_plausible = true;
|
retry_plausible = true;
|
||||||
/* Already reported something to gossipd, do not
|
|
||||||
* report anything else */
|
|
||||||
report_to_gossipd = false;
|
|
||||||
} else {
|
} else {
|
||||||
enum onion_type failcode = fromwire_peektype(reply->msg);
|
enum onion_type failcode = fromwire_peektype(reply->msg);
|
||||||
log_info(hout->key.channel->log,
|
log_info(hout->key.channel->log,
|
||||||
@@ -525,9 +430,8 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
hout->key.id,
|
hout->key.id,
|
||||||
reply->origin_index,
|
reply->origin_index,
|
||||||
failcode, onion_type_name(failcode));
|
failcode, onion_type_name(failcode));
|
||||||
fail = remote_routing_failure(tmpctx,
|
fail = remote_routing_failure(tmpctx, ld,
|
||||||
&retry_plausible,
|
&retry_plausible,
|
||||||
&report_to_gossipd,
|
|
||||||
payment, reply,
|
payment, reply,
|
||||||
hout->key.channel->log);
|
hout->key.channel->log);
|
||||||
}
|
}
|
||||||
@@ -545,15 +449,10 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
|||||||
fail ? fail->failcode : 0,
|
fail ? fail->failcode : 0,
|
||||||
fail ? &fail->erring_node : NULL,
|
fail ? &fail->erring_node : NULL,
|
||||||
fail ? &fail->erring_channel : NULL,
|
fail ? &fail->erring_channel : NULL,
|
||||||
fail ? fail->channel_update : NULL,
|
NULL,
|
||||||
failmsg,
|
failmsg,
|
||||||
fail ? fail->channel_dir : 0);
|
fail ? fail->channel_dir : 0);
|
||||||
|
|
||||||
/* Report to gossipd if we decided we should. */
|
|
||||||
if (report_to_gossipd)
|
|
||||||
report_routing_failure(ld->log, ld->gossip, fail);
|
|
||||||
|
|
||||||
|
|
||||||
/* Report to client. */
|
/* Report to client. */
|
||||||
payment_route_failure(ld, &hout->payment_hash,
|
payment_route_failure(ld, &hout->payment_hash,
|
||||||
retry_plausible, fail, hout->failuremsg,
|
retry_plausible, fail, hout->failuremsg,
|
||||||
@@ -642,7 +541,6 @@ bool wait_payment(const tal_t *cxt,
|
|||||||
fail->failcode = failcode;
|
fail->failcode = failcode;
|
||||||
fail->erring_node = *failnode;
|
fail->erring_node = *failnode;
|
||||||
fail->erring_channel = *failchannel;
|
fail->erring_channel = *failchannel;
|
||||||
fail->channel_update = failupdate;
|
|
||||||
fail->channel_dir = faildirection;
|
fail->channel_dir = faildirection;
|
||||||
result = sendpay_result_route_failure(tmpctx, !faildestperm, fail, NULL, faildetail);
|
result = sendpay_result_route_failure(tmpctx, !faildestperm, fail, NULL, faildetail);
|
||||||
}
|
}
|
||||||
@@ -763,7 +661,6 @@ send_payment(const tal_t *ctx,
|
|||||||
WIRE_UNKNOWN_NEXT_PEER,
|
WIRE_UNKNOWN_NEXT_PEER,
|
||||||
&route[0].channel_id,
|
&route[0].channel_id,
|
||||||
0);
|
0);
|
||||||
report_routing_failure(ld->log, ld->gossip, fail);
|
|
||||||
|
|
||||||
/* Report routing failure to caller */
|
/* Report routing failure to caller */
|
||||||
result = sendpay_result_route_failure(tmpctx, true, fail, NULL,
|
result = sendpay_result_route_failure(tmpctx, true, fail, NULL,
|
||||||
@@ -792,7 +689,6 @@ send_payment(const tal_t *ctx,
|
|||||||
failcode,
|
failcode,
|
||||||
&route[0].channel_id,
|
&route[0].channel_id,
|
||||||
&channel->peer->id);
|
&channel->peer->id);
|
||||||
report_routing_failure(ld->log, ld->gossip, fail);
|
|
||||||
|
|
||||||
/* Report routing failure to caller */
|
/* Report routing failure to caller */
|
||||||
result = sendpay_result_route_failure(tmpctx, true, fail, NULL,
|
result = sendpay_result_route_failure(tmpctx, true, fail, NULL,
|
||||||
@@ -917,9 +813,6 @@ static void json_waitsendpay_on_resolve(const struct sendpay_result *r,
|
|||||||
&fail->erring_channel);
|
&fail->erring_channel);
|
||||||
json_add_num(data, "erring_direction",
|
json_add_num(data, "erring_direction",
|
||||||
fail->channel_dir);
|
fail->channel_dir);
|
||||||
if (fail->channel_update)
|
|
||||||
json_add_hex_talarr(data, "channel_update",
|
|
||||||
fail->channel_update);
|
|
||||||
json_object_end(data);
|
json_object_end(data);
|
||||||
was_pending(command_failed(cmd, data));
|
was_pending(command_failed(cmd, data));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ struct routing_failure {
|
|||||||
struct pubkey erring_node;
|
struct pubkey erring_node;
|
||||||
struct short_channel_id erring_channel;
|
struct short_channel_id erring_channel;
|
||||||
int channel_dir;
|
int channel_dir;
|
||||||
u8 *channel_update;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Result of send_payment */
|
/* Result of send_payment */
|
||||||
|
|||||||
Reference in New Issue
Block a user