EXPERIMENTAL: dev-quiesce to initiate (and test) quiescence.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2021-05-31 12:38:04 +09:30 committed by neil saitug
parent e29c9c2fc0
commit 03cfe0b468
6 changed files with 164 additions and 4 deletions

View File

@ -297,9 +297,11 @@ static void maybe_send_stfu(struct peer *peer)
peer->stfu_sent[LOCAL] = true;
}
/* FIXME: We're finished, do something! */
if (peer->stfu_sent[LOCAL] && peer->stfu_sent[REMOTE])
if (peer->stfu_sent[LOCAL] && peer->stfu_sent[REMOTE]) {
status_unusual("STFU complete: we are quiescent");
wire_sync_write(MASTER_FD,
towire_channeld_dev_quiesce_reply(tmpctx));
}
}
static void handle_stfu(struct peer *peer, const u8 *stfu)
@ -3079,6 +3081,22 @@ static void channeld_send_custommsg(struct peer *peer, const u8 *msg)
master_badmsg(WIRE_CUSTOMMSG_OUT, msg);
sync_crypto_write(peer->pps, take(inner));
}
#if EXPERIMENTAL_FEATURES
static void handle_dev_quiesce(struct peer *peer, const u8 *msg)
{
if (!fromwire_channeld_dev_quiesce(msg))
master_badmsg(WIRE_CHANNELD_DEV_QUIESCE, msg);
/* Don't do this twice. */
if (peer->stfu)
status_failed(STATUS_FAIL_MASTER_IO, "dev_quiesce already");
peer->stfu = true;
peer->stfu_initiator = LOCAL;
maybe_send_stfu(peer);
}
#endif /* EXPERIMENTAL_FEATURES */
#endif /* DEVELOPER */
static void req_in(struct peer *peer, const u8 *msg)
@ -3127,9 +3145,15 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNELD_DEV_MEMLEAK:
handle_dev_memleak(peer, msg);
return;
case WIRE_CHANNELD_DEV_QUIESCE:
#if EXPERIMENTAL_FEATURES
handle_dev_quiesce(peer, msg);
return;
#endif /* EXPERIMENTAL_FEATURES */
#else
case WIRE_CHANNELD_DEV_REENABLE_COMMIT:
case WIRE_CHANNELD_DEV_MEMLEAK:
case WIRE_CHANNELD_DEV_QUIESCE:
#endif /* DEVELOPER */
case WIRE_CHANNELD_INIT:
case WIRE_CHANNELD_OFFER_HTLC_REPLY:
@ -3147,6 +3171,7 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNELD_FAIL_FALLEN_BEHIND:
case WIRE_CHANNELD_DEV_MEMLEAK_REPLY:
case WIRE_CHANNELD_SEND_ERROR_REPLY:
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:
break;
}

View File

@ -217,3 +217,7 @@ msgdata,channeld_send_error,reason,wirestring,
# Tell master channeld has sent the error message.
msgtype,channeld_send_error_reply,1108
# Ask channeld to quiesce.
msgtype,channeld_dev_quiesce,1009
msgtype,channeld_dev_quiesce_reply,1109

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

View File

@ -46,6 +46,8 @@ const char *channeld_wire_name(int e)
case WIRE_CHANNELD_GOT_ANNOUNCEMENT: return "WIRE_CHANNELD_GOT_ANNOUNCEMENT";
case WIRE_CHANNELD_SEND_ERROR: return "WIRE_CHANNELD_SEND_ERROR";
case WIRE_CHANNELD_SEND_ERROR_REPLY: return "WIRE_CHANNELD_SEND_ERROR_REPLY";
case WIRE_CHANNELD_DEV_QUIESCE: return "WIRE_CHANNELD_DEV_QUIESCE";
case WIRE_CHANNELD_DEV_QUIESCE_REPLY: return "WIRE_CHANNELD_DEV_QUIESCE_REPLY";
}
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
@ -81,6 +83,8 @@ bool channeld_wire_is_defined(u16 type)
case WIRE_CHANNELD_GOT_ANNOUNCEMENT:;
case WIRE_CHANNELD_SEND_ERROR:;
case WIRE_CHANNELD_SEND_ERROR_REPLY:;
case WIRE_CHANNELD_DEV_QUIESCE:;
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:;
return true;
}
return false;
@ -1070,4 +1074,43 @@ bool fromwire_channeld_send_error_reply(const void *p)
return false;
return cursor != NULL;
}
// SHA256STAMP:60143693b0c3611c8ecdf7f3549ef9f4c280e359cac0cd1f4df38cdca2dad3cb
/* WIRE: CHANNELD_DEV_QUIESCE */
/* Ask channeld to quiesce. */
u8 *towire_channeld_dev_quiesce(const tal_t *ctx)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_CHANNELD_DEV_QUIESCE);
return memcheck(p, tal_count(p));
}
bool fromwire_channeld_dev_quiesce(const void *p)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_CHANNELD_DEV_QUIESCE)
return false;
return cursor != NULL;
}
/* WIRE: CHANNELD_DEV_QUIESCE_REPLY */
u8 *towire_channeld_dev_quiesce_reply(const tal_t *ctx)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_CHANNELD_DEV_QUIESCE_REPLY);
return memcheck(p, tal_count(p));
}
bool fromwire_channeld_dev_quiesce_reply(const void *p)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_CHANNELD_DEV_QUIESCE_REPLY)
return false;
return cursor != NULL;
}
// SHA256STAMP:720f9917311384d373593dc1550619ddf461bdabde8b312ed6dc632cb7860c34

View File

@ -70,6 +70,9 @@ enum channeld_wire {
WIRE_CHANNELD_SEND_ERROR = 1008,
/* Tell master channeld has sent the error message. */
WIRE_CHANNELD_SEND_ERROR_REPLY = 1108,
/* Ask channeld to quiesce. */
WIRE_CHANNELD_DEV_QUIESCE = 1009,
WIRE_CHANNELD_DEV_QUIESCE_REPLY = 1109,
};
const char *channeld_wire_name(int e);
@ -211,6 +214,15 @@ bool fromwire_channeld_send_error(const tal_t *ctx, const void *p, wirestring **
u8 *towire_channeld_send_error_reply(const tal_t *ctx);
bool fromwire_channeld_send_error_reply(const void *p);
/* WIRE: CHANNELD_DEV_QUIESCE */
/* Ask channeld to quiesce. */
u8 *towire_channeld_dev_quiesce(const tal_t *ctx);
bool fromwire_channeld_dev_quiesce(const void *p);
/* WIRE: CHANNELD_DEV_QUIESCE_REPLY */
u8 *towire_channeld_dev_quiesce_reply(const tal_t *ctx);
bool fromwire_channeld_dev_quiesce_reply(const void *p);
#endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */
// SHA256STAMP:60143693b0c3611c8ecdf7f3549ef9f4c280e359cac0cd1f4df38cdca2dad3cb
// SHA256STAMP:720f9917311384d373593dc1550619ddf461bdabde8b312ed6dc632cb7860c34

View File

@ -425,11 +425,13 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNELD_FEERATES:
case WIRE_CHANNELD_SPECIFIC_FEERATES:
case WIRE_CHANNELD_DEV_MEMLEAK:
case WIRE_CHANNELD_DEV_QUIESCE:
/* Replies go to requests. */
case WIRE_CHANNELD_OFFER_HTLC_REPLY:
case WIRE_CHANNELD_DEV_REENABLE_COMMIT_REPLY:
case WIRE_CHANNELD_DEV_MEMLEAK_REPLY:
case WIRE_CHANNELD_SEND_ERROR:
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:
break;
}
@ -937,4 +939,54 @@ static const struct json_command dev_feerate_command = {
"Set feerate for {id} to {feerate}"
};
AUTODATA(json_command, &dev_feerate_command);
#if EXPERIMENTAL_FEATURES
static void quiesce_reply(struct subd *channeld UNUSED,
const u8 *reply,
const int *fds UNUSED,
struct command *cmd)
{
struct json_stream *response;
response = json_stream_success(cmd);
was_pending(command_success(cmd, response));
}
static struct command_result *json_dev_quiesce(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct node_id *id;
struct peer *peer;
struct channel *channel;
const u8 *msg;
if (!param(cmd, buffer, params,
p_req("id", param_node_id, &id),
NULL))
return command_param_failed();
peer = peer_by_id(cmd->ld, id);
if (!peer)
return command_fail(cmd, LIGHTNINGD, "Peer not connected");
channel = peer_active_channel(peer);
if (!channel || !channel->owner || channel->state != CHANNELD_NORMAL)
return command_fail(cmd, LIGHTNINGD, "Peer bad state");
msg = towire_channeld_dev_quiesce(NULL);
subd_req(channel->owner, channel->owner, take(msg), -1, 0,
quiesce_reply, cmd);
return command_still_pending(cmd);
}
static const struct json_command dev_quiesce_command = {
"dev-quiesce",
"developer",
json_dev_quiesce,
"Initiate quiscence protocol with peer"
};
AUTODATA(json_command, &dev_quiesce_command);
#endif /* EXPERIMENTAL_FEATURES */
#endif /* DEVELOPER */

View File

@ -3470,6 +3470,30 @@ def test_openchannel_init_alternate(node_factory, executor):
fut.result(10)
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "quiescence is experimental")
@pytest.mark.developer("quiescence triggering is dev only")
def test_quiescence(node_factory, executor):
l1, l2 = node_factory.line_graph(2)
# Works fine.
l1.pay(l2, 1000)
assert l1.rpc.call('dev-quiesce', [l2.info['id']]) == {}
# Both should consider themselves quiescent.
l1.daemon.wait_for_log("STFU complete: we are quiescent")
l2.daemon.wait_for_log("STFU complete: we are quiescent")
# Should not be able to increase fees.
l1.rpc.call('dev-feerate', [l2.info['id'], 9999])
try:
l1.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE', 5)
assert False
except TimeoutError:
pass
def test_htlc_failed_noclose(node_factory):
"""Test a bug where the htlc timeout would kick in even if the HTLC failed"""
l1, l2 = node_factory.line_graph(2)