lightningd: implement receiving warnings.

This takes from the draft spec at https://github.com/lightningnetwork/lightning-rfc/pull/834

Note that if this draft does not get included, the peer will simply
ignore the warning message (we always close the connection afterwards
anyway).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Protocol: we now report the new (draft) warning message.
This commit is contained in:
Rusty Russell
2021-02-02 23:16:01 +10:30
parent f0659d0ab0
commit a7c5a1f1d2
12 changed files with 55 additions and 20 deletions

View File

@@ -1928,6 +1928,7 @@ static void peer_in(struct peer *peer, const u8 *msg)
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
case WIRE_PING:
case WIRE_PONG:
case WIRE_WARNING:
case WIRE_ERROR:
case WIRE_ONION_MESSAGE:
abort();

View File

@@ -49,7 +49,7 @@ void peer_failed(struct per_peer_state *pps,
peer_fatal_continue(take(msg), pps);
}
/* We're failing because peer sent us an error message */
/* We're failing because peer sent us an error/warning message */
void peer_failed_received_errmsg(struct per_peer_state *pps,
const char *desc,
const struct channel_id *channel_id,
@@ -62,7 +62,7 @@ void peer_failed_received_errmsg(struct per_peer_state *pps,
channel_id = &all_channels;
msg = towire_status_peer_error(NULL, channel_id, desc, soft_error, pps,
NULL);
peer_billboard(true, "Received error from peer: %s", desc);
peer_billboard(true, "Received %s", desc);
peer_fatal_continue(take(msg), pps);
}

View File

@@ -69,11 +69,16 @@ u8 *peer_or_gossip_sync_read(const tal_t *ctx,
bool is_peer_error(const tal_t *ctx, const u8 *msg,
const struct channel_id *channel_id,
char **desc, bool *all_channels)
char **desc, bool *all_channels,
bool *warning)
{
struct channel_id err_chanid;
if (fromwire_peektype(msg) != WIRE_ERROR)
if (fromwire_peektype(msg) == WIRE_ERROR)
*warning = false;
else if (fromwire_peektype(msg) == WIRE_WARNING)
*warning = true;
else
return false;
*desc = sanitize_error(ctx, msg, &err_chanid);
@@ -154,7 +159,7 @@ bool handle_peer_gossip_or_error(struct per_peer_state *pps,
const u8 *msg TAKES)
{
char *err;
bool all_channels;
bool all_channels, warning;
struct channel_id actual;
#if DEVELOPER
@@ -181,12 +186,13 @@ bool handle_peer_gossip_or_error(struct per_peer_state *pps,
return true;
}
if (is_peer_error(tmpctx, msg, channel_id, &err, &all_channels)) {
if (is_peer_error(tmpctx, msg, channel_id, &err, &all_channels,
&warning)) {
if (err)
peer_failed_received_errmsg(pps, err,
all_channels
? NULL : channel_id,
soft_error);
warning || soft_error);
/* Ignore unknown channel errors. */
goto handled;

View File

@@ -34,13 +34,14 @@ u8 *peer_or_gossip_sync_read(const tal_t *ctx,
* @channel_id: the channel id of the current channel.
* @desc: set to non-NULL if this describes a channel we care about.
* @all_channels: set to true if this applies to all channels.
* @warning: set to true if this is a warning, not an error.
*
* If @desc is NULL, ignore this message. Otherwise, that's usually passed
* to peer_failed_received_errmsg().
*/
bool is_peer_error(const tal_t *ctx, const u8 *msg,
const struct channel_id *channel_id,
char **desc, bool *all_channels);
char **desc, bool *all_channels, bool *warning);
/**
* is_wrong_channel - if it's a message about a different channel, return true

View File

@@ -53,11 +53,16 @@ char *sanitize_error(const tal_t *ctx, const u8 *errmsg,
struct channel_id dummy;
u8 *data;
size_t i;
bool warning;
if (!channel_id)
channel_id = &dummy;
if (!fromwire_error(ctx, errmsg, channel_id, &data))
if (fromwire_error(ctx, errmsg, channel_id, &data))
warning = false;
else if (fromwire_warning(ctx, errmsg, channel_id, &data))
warning = true;
else
return tal_fmt(ctx, "Invalid ERROR message '%s'",
tal_hex(ctx, errmsg));
@@ -79,9 +84,10 @@ char *sanitize_error(const tal_t *ctx, const u8 *errmsg,
}
}
return tal_fmt(ctx, "channel %s: %.*s",
channel_id_is_all(channel_id)
? "ALL"
: type_to_string(ctx, struct channel_id, channel_id),
return tal_fmt(ctx, "%s%s%s: %.*s",
warning ? "warning" : "error",
channel_id_is_all(channel_id) ? "": " channel ",
channel_id_is_all(channel_id) ? ""
: type_to_string(tmpctx, struct channel_id, channel_id),
(int)tal_count(data), (char *)data);
}

View File

@@ -43,10 +43,10 @@ u8 *towire_errorfmtv(const tal_t *ctx,
bool channel_id_is_all(const struct channel_id *channel_id);
/**
* sanitize_error - extract and sanitize contents of WIRE_ERROR.
* sanitize_error - extract and sanitize contents of WIRE_ERROR/WIRE_WARNING.
*
* @ctx: context to allocate from
* @errmsg: the wire_error
* @errmsg: the wire_error or wire_warning
* @channel: (out) channel it's referring to, or NULL if don't care.
*/
char *sanitize_error(const tal_t *ctx, const u8 *errmsg,

View File

@@ -737,6 +737,7 @@ static struct io_plan *peer_msg_in(struct io_conn *conn,
goto handled_relay;
/* These are non-gossip messages (!is_msg_for_gossipd()) */
case WIRE_WARNING:
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_OPEN_CHANNEL:

View File

@@ -972,7 +972,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state)
u8 *msg;
bool from_gossipd;
char *err;
bool all_channels;
bool all_channels, warning;
struct channel_id actual;
/* The event loop is responsible for freeing tmpctx, so our
@@ -1011,7 +1011,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state)
/* A helper which decodes an error. */
if (is_peer_error(tmpctx, msg, &state->channel_id,
&err, &all_channels)) {
&err, &all_channels, &warning)) {
/* BOLT #1:
*
* - if no existing channel is referred to by the
@@ -1355,6 +1355,7 @@ static bool run_tx_interactive(struct state *state,
break;
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_WARNING:
case WIRE_OPEN_CHANNEL:
case WIRE_ACCEPT_CHANNEL:
case WIRE_FUNDING_CREATED:

View File

@@ -199,7 +199,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state,
u8 *msg;
bool from_gossipd;
char *err;
bool all_channels;
bool all_channels, warning;
struct channel_id actual;
/* The event loop is responsible for freeing tmpctx, so our
@@ -238,7 +238,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state,
/* A helper which decodes an error. */
if (is_peer_error(tmpctx, msg, &state->channel_id,
&err, &all_channels)) {
&err, &all_channels, &warning)) {
/* BOLT #1:
*
* - if no existing channel is referred to by the
@@ -262,7 +262,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state,
NULL, false);
}
negotiation_aborted(state, am_opener,
tal_fmt(tmpctx, "They sent error %s",
tal_fmt(tmpctx, "They sent %s",
err));
/* Return NULL so caller knows to stop negotiating. */
return NULL;

View File

@@ -0,0 +1,13 @@
--- wire/peer_exp_wire.csv 2021-01-14 11:00:27.526336550 +1030
+++ - 2021-01-21 15:31:37.071118999 +1030
@@ -10,6 +10,10 @@
msgdata,error,channel_id,channel_id,
msgdata,error,len,u16,
msgdata,error,data,byte,len
+msgtype,warning,1
+msgdata,warning,channel_id,channel_id,
+msgdata,warning,len,u16,
+msgdata,warning,data,byte,len
msgtype,ping,18
msgdata,ping,num_pong_bytes,u16,
msgdata,ping,byteslen,u16,

View File

@@ -4,6 +4,7 @@
static bool unknown_type(enum peer_wire t)
{
switch (t) {
case WIRE_WARNING:
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_OPEN_CHANNEL:
@@ -64,6 +65,7 @@ bool is_msg_for_gossipd(const u8 *cursor)
case WIRE_PONG:
case WIRE_ONION_MESSAGE:
return true;
case WIRE_WARNING:
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_OPEN_CHANNEL:

View File

@@ -10,6 +10,10 @@ msgtype,error,17
msgdata,error,channel_id,channel_id,
msgdata,error,len,u16,
msgdata,error,data,byte,len
msgtype,warning,1
msgdata,warning,channel_id,channel_id,
msgdata,warning,len,u16,
msgdata,warning,data,byte,len
msgtype,ping,18
msgdata,ping,num_pong_bytes,u16,
msgdata,ping,byteslen,u16,
1 msgtype,init,16
10 msgdata,error,channel_id,channel_id,
11 msgdata,error,len,u16,
12 msgdata,error,data,byte,len
13 msgtype,warning,1
14 msgdata,warning,channel_id,channel_id,
15 msgdata,warning,len,u16,
16 msgdata,warning,data,byte,len
17 msgtype,ping,18
18 msgdata,ping,num_pong_bytes,u16,
19 msgdata,ping,byteslen,u16,