Browse Source

gossip: Disable channels when we lose the connection to the peer

We're telling gossipd about disconnections anyway, so let's just use that signal
to disable both sides of the channel.

Signed-off-by: Christian Decker <decker.christian@gmail.com>
ppa-0.6.1
Christian Decker 7 years ago
committed by Rusty Russell
parent
commit
8e278044e3
  1. 183
      gossipd/gossip.c
  2. 6
      gossipd/gossip_wire.csv
  3. 8
      lightningd/channel.c
  4. 1
      lightningd/gossip_control.c
  5. 5
      wallet/test/run-wallet.c

183
gossipd/gossip.c

@ -2355,11 +2355,99 @@ static struct io_plan *peer_important(struct io_conn *conn,
return daemon_conn_read_next(conn, &daemon->master);
}
static void gossip_disable_channel(struct routing_state *rstate, struct chan *chan)
{
struct short_channel_id scid;
u8 direction;
struct half_chan *hc;
u16 flags, cltv_expiry_delta;
u32 timestamp, fee_base_msat, fee_proportional_millionths;
struct bitcoin_blkid chain_hash;
secp256k1_ecdsa_signature sig;
u64 htlc_minimum_msat;
u8 *err, *msg;
direction = pubkey_eq(&chan->nodes[0]->id, &rstate->local_id)?0:1;
assert(chan);
hc = &chan->half[direction];
status_trace("Disabling channel %s/%d, active %d -> %d",
type_to_string(tmpctx, struct short_channel_id, &chan->scid),
direction, is_halfchan_enabled(hc), 0);
if (!is_halfchan_defined(hc)) {
status_trace(
"Channel %s/%d doesn't have a channel_update yet, can't "
"disable",
type_to_string(tmpctx, struct short_channel_id, &scid),
direction);
return;
}
if (!fromwire_channel_update(
hc->channel_update, &sig, &chain_hash, &scid, &timestamp,
&flags, &cltv_expiry_delta, &htlc_minimum_msat, &fee_base_msat,
&fee_proportional_millionths)) {
status_failed(
STATUS_FAIL_INTERNAL_ERROR,
"Unable to parse previously accepted channel_update");
}
status_trace("Disabling channel %s", type_to_string(tmpctx, struct short_channel_id, &scid));
timestamp = time_now().ts.tv_sec;
if (timestamp <= hc->last_timestamp)
timestamp = hc->last_timestamp + 1;
status_trace("Disabling channel %s: %d", type_to_string(tmpctx, struct short_channel_id, &scid), 0);
flags = flags | ROUTING_FLAGS_DISABLED;
msg = towire_channel_update(tmpctx, &sig, &chain_hash, &scid, timestamp,
flags, cltv_expiry_delta, htlc_minimum_msat,
fee_base_msat, fee_proportional_millionths);
if (!wire_sync_write(HSM_FD,
towire_hsm_cupdate_sig_req(tmpctx, msg))) {
status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s",
strerror(errno));
}
msg = wire_sync_read(tmpctx, HSM_FD);
if (!msg || !fromwire_hsm_cupdate_sig_reply(tmpctx, msg, &msg)) {
status_failed(STATUS_FAIL_HSM_IO,
"Reading cupdate_sig_req: %s",
strerror(errno));
}
err = handle_channel_update(rstate, msg, "disable_channel");
if (err)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"rejected disabling channel_update: %s",
tal_hex(tmpctx, err));
}
static void peer_disable_channels(struct routing_state *rstate, struct node *node)
{
struct chan *c;
size_t i;
for (i=0; i<tal_count(node->chans); i++) {
c = node->chans[i];
if (pubkey_eq(&other_node(node, c)->id, &rstate->local_id)) {
c->half[0].flags |= ROUTING_FLAGS_DISABLED;
c->half[1].flags |= ROUTING_FLAGS_DISABLED;
gossip_disable_channel(rstate, c);
}
}
}
static struct io_plan *peer_disconnected(struct io_conn *conn,
struct daemon *daemon, const u8 *msg)
{
struct pubkey id;
struct peer *peer;
struct node *node;
if (!fromwire_gossipctl_peer_disconnected(msg, &id))
master_badmsg(WIRE_GOSSIPCTL_PEER_DISCONNECTED, msg);
@ -2375,6 +2463,11 @@ static struct io_plan *peer_disconnected(struct io_conn *conn,
status_trace("Forgetting remote peer %s",
type_to_string(tmpctx, struct pubkey, &peer->id));
/* Disable any channels to and from this peer */
node = get_node(daemon->rstate, &id);
if (node)
peer_disable_channels(daemon->rstate, node);
tal_free(peer);
/* If there was a connecting peer waiting, wake it now */
@ -2440,92 +2533,6 @@ static struct io_plan *handle_txout_reply(struct io_conn *conn,
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *handle_disable_channel(struct io_conn *conn,
struct daemon *daemon, u8 *msg)
{
struct short_channel_id scid;
u8 direction;
struct chan *chan;
struct half_chan *hc;
bool active;
u16 flags, cltv_expiry_delta;
u32 timestamp, fee_base_msat, fee_proportional_millionths;
struct bitcoin_blkid chain_hash;
secp256k1_ecdsa_signature sig;
u64 htlc_minimum_msat;
u8 *err;
if (!fromwire_gossip_disable_channel(msg, &scid, &direction, &active) ) {
status_unusual("Unable to parse %s",
gossip_wire_type_name(fromwire_peektype(msg)));
goto fail;
}
chan = get_channel(daemon->rstate, &scid);
if (!chan) {
status_trace(
"Unable to find channel %s",
type_to_string(msg, struct short_channel_id, &scid));
goto fail;
}
hc = &chan->half[direction];
status_trace("Disabling channel %s/%d, active %d -> %d",
type_to_string(msg, struct short_channel_id, &scid),
direction, is_halfchan_enabled(hc), active);
if (!is_halfchan_defined(hc)) {
status_trace(
"Channel %s/%d doesn't have a channel_update yet, can't "
"disable",
type_to_string(msg, struct short_channel_id, &scid),
direction);
goto fail;
}
if (!fromwire_channel_update(
hc->channel_update, &sig, &chain_hash, &scid, &timestamp,
&flags, &cltv_expiry_delta, &htlc_minimum_msat, &fee_base_msat,
&fee_proportional_millionths)) {
status_failed(
STATUS_FAIL_INTERNAL_ERROR,
"Unable to parse previously accepted channel_update");
}
timestamp = time_now().ts.tv_sec;
if (timestamp <= hc->last_timestamp)
timestamp = hc->last_timestamp + 1;
flags = direction;
if (!active)
flags |= ROUTING_FLAGS_DISABLED;
msg = towire_channel_update(tmpctx, &sig, &chain_hash, &scid, timestamp,
flags, cltv_expiry_delta, htlc_minimum_msat,
fee_base_msat, fee_proportional_millionths);
if (!wire_sync_write(HSM_FD,
towire_hsm_cupdate_sig_req(tmpctx, msg))) {
status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s",
strerror(errno));
}
msg = wire_sync_read(tmpctx, HSM_FD);
if (!msg || !fromwire_hsm_cupdate_sig_reply(tmpctx, msg, &msg)) {
status_failed(STATUS_FAIL_HSM_IO,
"Reading cupdate_sig_req: %s",
strerror(errno));
}
err = handle_channel_update(daemon->rstate, msg, "disable_channel");
if (err)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"rejected disabling channel_update: %s",
tal_hex(tmpctx, err));
fail:
return daemon_conn_read_next(conn, &daemon->master);
}
static struct io_plan *handle_routing_failure(struct io_conn *conn,
struct daemon *daemon,
const u8 *msg)
@ -2615,6 +2622,7 @@ static struct io_plan *handle_local_channel_close(struct io_conn *conn,
if (chan) {
chan->half[0].flags |= ROUTING_FLAGS_DISABLED;
chan->half[1].flags |= ROUTING_FLAGS_DISABLED;
gossip_disable_channel(rstate, chan);
}
return daemon_conn_read_next(conn, &daemon->master);
}
@ -2670,9 +2678,6 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master
case WIRE_GOSSIP_GET_TXOUT_REPLY:
return handle_txout_reply(conn, daemon, master->msg_in);
case WIRE_GOSSIP_DISABLE_CHANNEL:
return handle_disable_channel(conn, daemon, master->msg_in);
case WIRE_GOSSIP_ROUTING_FAILURE:
return handle_routing_failure(conn, daemon, master->msg_in);

6
gossipd/gossip_wire.csv

@ -220,12 +220,6 @@ gossip_get_txout_reply,,satoshis,u64
gossip_get_txout_reply,,len,u16
gossip_get_txout_reply,,outscript,len*u8
# client->gossipd: Disable the channel matching the short_channel_id
gossip_disable_channel,3019
gossip_disable_channel,,short_channel_id,struct short_channel_id
gossip_disable_channel,,direction,u8
gossip_disable_channel,,active,bool
# master->gossipd a routing failure occurred
gossip_routing_failure,3021
gossip_routing_failure,,erring_node,struct pubkey

Can't render this file because it has a wrong number of fields in line 6.

8
lightningd/channel.c

@ -329,14 +329,6 @@ void channel_fail_permanent(struct channel *channel, const char *fmt, ...)
why = tal_vfmt(channel, fmt, ap);
va_end(ap);
if (channel->scid) {
u8 *msg = towire_gossip_disable_channel(NULL,
channel->scid,
channel->peer->direction,
false);
subd_send_msg(ld->gossip, take(msg));
}
log_unusual(channel->log, "Peer permanent failure in %s: %s",
channel_state_name(channel), why);

1
lightningd/gossip_control.c

@ -133,7 +133,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIP_GET_UPDATE:
case WIRE_GOSSIP_SEND_GOSSIP:
case WIRE_GOSSIP_GET_TXOUT_REPLY:
case WIRE_GOSSIP_DISABLE_CHANNEL:
case WIRE_GOSSIP_OUTPOINT_SPENT:
case WIRE_GOSSIP_ROUTING_FAILURE:
case WIRE_GOSSIP_MARK_CHANNEL_UNROUTABLE:

5
wallet/test/run-wallet.c

@ -52,7 +52,7 @@ bool channel_tell_funding_locked(struct lightningd *ld UNNEEDED,
{ fprintf(stderr, "channel_tell_funding_locked called!\n"); abort(); }
/* Generated stub for command_fail */
void command_fail(struct command *cmd UNNEEDED, int code UNNEEDED,
const char *fmt UNNEEDED, ...)
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "command_fail called!\n"); abort(); }
/* Generated stub for command_still_pending */
void command_still_pending(struct command *cmd UNNEEDED)
@ -388,9 +388,6 @@ u8 *towire_gossipctl_peer_disconnected(const tal_t *ctx UNNEEDED, const struct p
/* Generated stub for towire_gossipctl_peer_important */
u8 *towire_gossipctl_peer_important(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED, bool important UNNEEDED)
{ fprintf(stderr, "towire_gossipctl_peer_important called!\n"); abort(); }
/* Generated stub for towire_gossip_disable_channel */
u8 *towire_gossip_disable_channel(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED, u8 direction UNNEEDED, bool active UNNEEDED)
{ fprintf(stderr, "towire_gossip_disable_channel called!\n"); abort(); }
/* Generated stub for towire_gossip_getpeers_request */
u8 *towire_gossip_getpeers_request(const tal_t *ctx UNNEEDED, const struct pubkey *id UNNEEDED)
{ fprintf(stderr, "towire_gossip_getpeers_request called!\n"); abort(); }

Loading…
Cancel
Save