gossipd: don't mark channels unroutable.
For transient failures, the pay plugin should simply exclude those from route considerations. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
018a3f1d58
commit
4eddf57fd9
|
@ -126,11 +126,6 @@ gossip_routing_failure,,failcode,u16
|
||||||
gossip_routing_failure,,len,u16
|
gossip_routing_failure,,len,u16
|
||||||
gossip_routing_failure,,channel_update,len*u8
|
gossip_routing_failure,,channel_update,len*u8
|
||||||
|
|
||||||
# master->gossipd temporarily mark a channel unroutable
|
|
||||||
# (used in case of unparseable onion reply)
|
|
||||||
gossip_mark_channel_unroutable,3022
|
|
||||||
gossip_mark_channel_unroutable,,channel,struct short_channel_id
|
|
||||||
|
|
||||||
# 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
|
||||||
gossip_outpoint_spent,,short_channel_id,struct short_channel_id
|
gossip_outpoint_spent,,short_channel_id,struct short_channel_id
|
||||||
|
|
|
|
@ -2540,24 +2540,6 @@ static struct io_plan *handle_routing_failure(struct io_conn *conn,
|
||||||
return daemon_conn_read_next(conn, daemon->master);
|
return daemon_conn_read_next(conn, daemon->master);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*~ This allows lightningd to explicitly mark a channel temporarily unroutable.
|
|
||||||
* This is used when we get an unparsable error, and we don't know who to blame;
|
|
||||||
* lightningd uses this to marking routes unroutable at random... */
|
|
||||||
static struct io_plan *
|
|
||||||
handle_mark_channel_unroutable(struct io_conn *conn,
|
|
||||||
struct daemon *daemon,
|
|
||||||
const u8 *msg)
|
|
||||||
{
|
|
||||||
struct short_channel_id channel;
|
|
||||||
|
|
||||||
if (!fromwire_gossip_mark_channel_unroutable(msg, &channel))
|
|
||||||
master_badmsg(WIRE_GOSSIP_MARK_CHANNEL_UNROUTABLE, msg);
|
|
||||||
|
|
||||||
mark_channel_unroutable(daemon->rstate, &channel);
|
|
||||||
|
|
||||||
return daemon_conn_read_next(conn, daemon->master);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*~ This is where lightningd tells us that a channel's funding transaction has
|
/*~ This is where lightningd tells us that a channel's funding transaction has
|
||||||
* been spent. */
|
* been spent. */
|
||||||
static struct io_plan *handle_outpoint_spent(struct io_conn *conn,
|
static struct io_plan *handle_outpoint_spent(struct io_conn *conn,
|
||||||
|
@ -2642,9 +2624,6 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
||||||
case WIRE_GOSSIP_ROUTING_FAILURE:
|
case WIRE_GOSSIP_ROUTING_FAILURE:
|
||||||
return handle_routing_failure(conn, daemon, msg);
|
return handle_routing_failure(conn, daemon, msg);
|
||||||
|
|
||||||
case WIRE_GOSSIP_MARK_CHANNEL_UNROUTABLE:
|
|
||||||
return handle_mark_channel_unroutable(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);
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,6 @@ static void init_half_chan(struct routing_state *rstate,
|
||||||
struct half_chan *c = &chan->half[channel_idx];
|
struct half_chan *c = &chan->half[channel_idx];
|
||||||
|
|
||||||
c->channel_update = NULL;
|
c->channel_update = NULL;
|
||||||
c->unroutable_until = 0;
|
|
||||||
|
|
||||||
/* Set the channel direction */
|
/* Set the channel direction */
|
||||||
c->channel_flags = channel_idx;
|
c->channel_flags = channel_idx;
|
||||||
|
@ -438,11 +437,10 @@ static void bfg_one_edge(struct node *node,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine if the given half_chan is routable */
|
/* Determine if the given half_chan is routable */
|
||||||
static bool hc_is_routable(const struct chan *chan, int idx, time_t now)
|
static bool hc_is_routable(const struct chan *chan, int idx)
|
||||||
{
|
{
|
||||||
return !chan->local_disabled
|
return !chan->local_disabled
|
||||||
&& is_halfchan_enabled(&chan->half[idx])
|
&& is_halfchan_enabled(&chan->half[idx]);
|
||||||
&& chan->half[idx].unroutable_until < now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* riskfactor is already scaled to per-block amount */
|
/* riskfactor is already scaled to per-block amount */
|
||||||
|
@ -458,10 +456,6 @@ find_route(const tal_t *ctx, struct routing_state *rstate,
|
||||||
struct node *n, *src, *dst;
|
struct node *n, *src, *dst;
|
||||||
struct node_map_iter it;
|
struct node_map_iter it;
|
||||||
int runs, i, best;
|
int runs, i, best;
|
||||||
/* Call time_now() once at the start, so that our tight loop
|
|
||||||
* does not keep calling into operating system for the
|
|
||||||
* current time */
|
|
||||||
time_t now = time_now().ts.tv_sec;
|
|
||||||
|
|
||||||
/* Note: we map backwards, since we know the amount of satoshi we want
|
/* Note: we map backwards, since we know the amount of satoshi we want
|
||||||
* at the end, and need to derive how much we need to send. */
|
* at the end, and need to derive how much we need to send. */
|
||||||
|
@ -518,7 +512,7 @@ find_route(const tal_t *ctx, struct routing_state *rstate,
|
||||||
&n->id),
|
&n->id),
|
||||||
i, num_edges);
|
i, num_edges);
|
||||||
|
|
||||||
if (!hc_is_routable(chan, idx, now)) {
|
if (!hc_is_routable(chan, idx)) {
|
||||||
SUPERVERBOSE("...unroutable (local_disabled = %i, is_halfchan_enabled = %i, unroutable_until = %i",
|
SUPERVERBOSE("...unroutable (local_disabled = %i, is_halfchan_enabled = %i, unroutable_until = %i",
|
||||||
chan->local_disabled,
|
chan->local_disabled,
|
||||||
is_halfchan_enabled(&chan->half[idx]),
|
is_halfchan_enabled(&chan->half[idx]),
|
||||||
|
@ -1040,9 +1034,6 @@ static void set_connection_values(struct chan *chan,
|
||||||
c->last_timestamp = timestamp;
|
c->last_timestamp = timestamp;
|
||||||
assert((c->channel_flags & ROUTING_FLAGS_DIRECTION) == idx);
|
assert((c->channel_flags & ROUTING_FLAGS_DIRECTION) == idx);
|
||||||
|
|
||||||
/* If it was temporarily unroutable, re-enable */
|
|
||||||
c->unroutable_until = 0;
|
|
||||||
|
|
||||||
SUPERVERBOSE("Channel %s/%d was updated.",
|
SUPERVERBOSE("Channel %s/%d was updated.",
|
||||||
type_to_string(tmpctx, struct short_channel_id, &chan->scid),
|
type_to_string(tmpctx, struct short_channel_id, &chan->scid),
|
||||||
idx);
|
idx);
|
||||||
|
@ -1583,17 +1574,12 @@ static void routing_failure_channel_out(const tal_t *disposal_context,
|
||||||
struct chan *chan,
|
struct chan *chan,
|
||||||
time_t now)
|
time_t now)
|
||||||
{
|
{
|
||||||
struct half_chan *hc = half_chan_from(node, chan);
|
|
||||||
|
|
||||||
/* BOLT #4:
|
/* BOLT #4:
|
||||||
*
|
*
|
||||||
* - if the PERM bit is NOT set:
|
* - if the PERM bit is NOT set:
|
||||||
* - SHOULD restore the channels as it receives new `channel_update`s.
|
* - SHOULD restore the channels as it receives new `channel_update`s.
|
||||||
*/
|
*/
|
||||||
if (!(failcode & PERM))
|
if (failcode & PERM)
|
||||||
/* Prevent it for 20 seconds. */
|
|
||||||
hc->unroutable_until = now + 20;
|
|
||||||
else
|
|
||||||
/* Set it up to be pruned. */
|
/* Set it up to be pruned. */
|
||||||
tal_steal(disposal_context, chan);
|
tal_steal(disposal_context, chan);
|
||||||
}
|
}
|
||||||
|
@ -1692,27 +1678,6 @@ void routing_failure(struct routing_state *rstate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mark_channel_unroutable(struct routing_state *rstate,
|
|
||||||
const struct short_channel_id *channel)
|
|
||||||
{
|
|
||||||
struct chan *chan;
|
|
||||||
time_t now = time_now().ts.tv_sec;
|
|
||||||
const char *scid = type_to_string(tmpctx, struct short_channel_id,
|
|
||||||
channel);
|
|
||||||
|
|
||||||
status_trace("Received mark_channel_unroutable channel %s",
|
|
||||||
scid);
|
|
||||||
|
|
||||||
chan = get_channel(rstate, channel);
|
|
||||||
if (!chan) {
|
|
||||||
status_unusual("mark_channel_unroutable: "
|
|
||||||
"channel %s not in routemap",
|
|
||||||
scid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
chan->half[0].unroutable_until = now + 20;
|
|
||||||
chan->half[1].unroutable_until = now + 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
void route_prune(struct routing_state *rstate)
|
void route_prune(struct routing_state *rstate)
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,10 +39,6 @@ struct half_chan {
|
||||||
/* Flags as specified by the `channel_update`s, indicates
|
/* Flags as specified by the `channel_update`s, indicates
|
||||||
* optional fields. */
|
* optional fields. */
|
||||||
u8 message_flags;
|
u8 message_flags;
|
||||||
|
|
||||||
/* If greater than current time, this connection should not
|
|
||||||
* be used for routing. */
|
|
||||||
time_t unroutable_until;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct chan {
|
struct chan {
|
||||||
|
@ -277,9 +273,6 @@ void routing_failure(struct routing_state *rstate,
|
||||||
const struct short_channel_id *erring_channel,
|
const struct short_channel_id *erring_channel,
|
||||||
enum onion_type failcode,
|
enum onion_type failcode,
|
||||||
const u8 *channel_update);
|
const u8 *channel_update);
|
||||||
/* Disable specific channel from routing. */
|
|
||||||
void mark_channel_unroutable(struct routing_state *rstate,
|
|
||||||
const struct short_channel_id *channel);
|
|
||||||
|
|
||||||
void route_prune(struct routing_state *rstate);
|
void route_prune(struct routing_state *rstate);
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
|
||||||
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_ROUTING_FAILURE:
|
||||||
case WIRE_GOSSIP_MARK_CHANNEL_UNROUTABLE:
|
|
||||||
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:
|
||||||
|
|
|
@ -394,31 +394,6 @@ remote_routing_failure(const tal_t *ctx,
|
||||||
return routing_failure;
|
return routing_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void random_mark_channel_unroutable(struct log *log,
|
|
||||||
struct subd *gossip,
|
|
||||||
struct short_channel_id *route_channels)
|
|
||||||
{
|
|
||||||
size_t num_channels = tal_count(route_channels);
|
|
||||||
size_t i;
|
|
||||||
const struct short_channel_id *channel;
|
|
||||||
u8 *msg;
|
|
||||||
assert(num_channels != 0);
|
|
||||||
|
|
||||||
/* Select one channel by random. */
|
|
||||||
randombytes_buf(&i, sizeof(i));
|
|
||||||
i = i % num_channels;
|
|
||||||
channel = &route_channels[i];
|
|
||||||
|
|
||||||
log_debug(log,
|
|
||||||
"Disable randomly %dth channel (%s) along route "
|
|
||||||
"(guessing due to bad reply)",
|
|
||||||
(int) i,
|
|
||||||
type_to_string(tmpctx, struct short_channel_id,
|
|
||||||
channel));
|
|
||||||
msg = towire_gossip_mark_channel_unroutable(tmpctx, channel);
|
|
||||||
subd_send_msg(gossip, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void report_routing_failure(struct log *log,
|
static void report_routing_failure(struct log *log,
|
||||||
struct subd *gossip,
|
struct subd *gossip,
|
||||||
struct routing_failure *fail)
|
struct routing_failure *fail)
|
||||||
|
@ -535,10 +510,6 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
|
||||||
tal_hex(tmpctx, hout->failuremsg));
|
tal_hex(tmpctx, hout->failuremsg));
|
||||||
/* Cannot report failure. */
|
/* Cannot report failure. */
|
||||||
fail = NULL;
|
fail = NULL;
|
||||||
/* Select a channel to mark unroutable by random */
|
|
||||||
random_mark_channel_unroutable(hout->key.channel->log,
|
|
||||||
ld->gossip,
|
|
||||||
payment->route_channels);
|
|
||||||
/* Can now retry; we selected a channel to mark
|
/* Can now retry; we selected a channel to mark
|
||||||
* unroutable by random */
|
* unroutable by random */
|
||||||
retry_plausible = true;
|
retry_plausible = true;
|
||||||
|
|
Loading…
Reference in New Issue